Reference documentation for deal.II version 9.3.2
\(\newcommand{\dealvcentcolon}{\mathrel{\mathop{:}}}\) \(\newcommand{\dealcoloneq}{\dealvcentcolon\mathrel{\mkern-1.2mu}=}\) \(\newcommand{\jump}[1]{\left[\!\left[ #1 \right]\!\right]}\) \(\newcommand{\average}[1]{\left\{\!\left\{ #1 \right\}\!\right\}}\)
mpi_remote_point_evaluation.h
Go to the documentation of this file.
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 2021 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.md at
12 // the top level directory of deal.II.
13 //
14 // ---------------------------------------------------------------------
15 
16 #ifndef dealii_mpi_mpi_remote_point_evaluation_h
17 #define dealii_mpi_mpi_remote_point_evaluation_h
18 
19 #include <deal.II/base/config.h>
20 
22 
25 
27 
28 
29 namespace Utilities
30 {
31  namespace MPI
32  {
43  template <int dim, int spacedim = dim>
45  {
46  public:
59  RemotePointEvaluation(const double tolerance = 1e-6,
60  const bool enforce_unique_mapping = false);
61 
66 
72  void
73  reinit(const std::vector<Point<spacedim>> &points,
76 
80  struct CellData
81  {
85  std::vector<std::pair<int, int>> cells;
86 
91  std::vector<unsigned int> reference_point_ptrs;
92 
96  std::vector<Point<dim>> reference_point_values;
97  };
98 
110  template <typename T>
111  void
113  std::vector<T> &output,
114  std::vector<T> &buffer,
115  const std::function<void(const ArrayView<T> &, const CellData &)>
116  &evaluation_function) const;
117 
123  template <typename T>
124  void
126  const std::vector<T> &input,
127  std::vector<T> & buffer,
128  const std::function<void(const ArrayView<const T> &, const CellData &)>
129  &evaluation_function) const;
130 
135  const std::vector<unsigned int> &
136  get_point_ptrs() const;
137 
144  bool
145  is_map_unique() const;
146 
151  get_triangulation() const;
152 
156  const Mapping<dim, spacedim> &
157  get_mapping() const;
158 
164  bool
165  is_ready() const;
166 
167  private:
172  const double tolerance;
173 
179 
183  boost::signals2::connection tria_signal;
184 
191 
196 
201 
206 
212  std::vector<unsigned int> point_ptrs;
213 
217  std::vector<unsigned int> recv_permutation;
218 
223  std::vector<unsigned int> recv_ptrs;
224 
228  std::vector<unsigned int> recv_ranks;
229 
235 
239  std::vector<unsigned int> send_permutation;
240 
244  std::vector<unsigned int> send_ranks;
245 
250  std::vector<unsigned int> send_ptrs;
251  };
252 
253 
254  template <int dim, int spacedim>
255  template <typename T>
256  void
258  std::vector<T> &output,
259  std::vector<T> &buffer,
260  const std::function<void(const ArrayView<T> &, const CellData &)>
261  &evaluation_function) const
262  {
263 #ifndef DEAL_II_WITH_MPI
264  Assert(false, ExcNeedsMPI());
265  (void)output;
266  (void)buffer;
267  (void)evaluation_function;
268 #else
269  static CollectiveMutex mutex;
270  CollectiveMutex::ScopedLock lock(mutex, tria->get_communicator());
271 
272  output.resize(point_ptrs.back());
273  buffer.resize(send_permutation.size() * 2);
274  ArrayView<T> buffer_1(buffer.data(), buffer.size() / 2);
275  ArrayView<T> buffer_2(buffer.data() + buffer.size() / 2,
276  buffer.size() / 2);
277 
278  // evaluate functions at points
279  evaluation_function(buffer_1, cell_data);
280 
281  // sort for communication
282  for (unsigned int i = 0; i < send_permutation.size(); ++i)
283  buffer_2[send_permutation[i]] = buffer_1[i];
284 
285  // process remote quadrature points and send them away
286  std::map<unsigned int, std::vector<char>> temp_map;
287 
288  std::vector<MPI_Request> requests;
289  requests.reserve(send_ranks.size());
290 
291  const unsigned int my_rank =
293 
294  std::map<unsigned int, std::vector<T>> temp_recv_map;
295 
296  for (unsigned int i = 0; i < send_ranks.size(); ++i)
297  {
298  if (send_ranks[i] == my_rank)
299  {
300  // process locally-owned values
301  temp_recv_map[my_rank] =
302  std::vector<T>(buffer_2.begin() + send_ptrs[i],
303  buffer_2.begin() + send_ptrs[i + 1]);
304  continue;
305  }
306 
307  temp_map[send_ranks[i]] =
308  Utilities::pack(std::vector<T>(buffer_2.begin() + send_ptrs[i],
309  buffer_2.begin() + send_ptrs[i + 1]),
310  false);
311 
312  auto &buffer = temp_map[send_ranks[i]];
313 
314  requests.push_back(MPI_Request());
315 
316  MPI_Isend(buffer.data(),
317  buffer.size(),
318  MPI_CHAR,
319  send_ranks[i],
321  tria->get_communicator(),
322  &requests.back());
323  }
324 
325  for (const auto recv_rank : recv_ranks)
326  {
327  if (recv_rank == my_rank)
328  continue;
329 
330  MPI_Status status;
331  MPI_Probe(MPI_ANY_SOURCE,
333  tria->get_communicator(),
334  &status);
335 
336  int message_length;
337  MPI_Get_count(&status, MPI_CHAR, &message_length);
338 
339  std::vector<char> buffer(message_length);
340 
341  MPI_Recv(buffer.data(),
342  buffer.size(),
343  MPI_CHAR,
344  status.MPI_SOURCE,
346  tria->get_communicator(),
347  MPI_STATUS_IGNORE);
348 
349  temp_recv_map[status.MPI_SOURCE] =
350  Utilities::unpack<std::vector<T>>(buffer, false);
351  }
352 
353  // make sure all messages have been sent
354  MPI_Waitall(requests.size(), requests.data(), MPI_STATUSES_IGNORE);
355 
356  // copy received data into output vector
357  auto it = recv_permutation.begin();
358  for (const auto &j : temp_recv_map)
359  for (const auto &i : j.second)
360  {
361  output[*it] = i;
362  it++;
363  }
364 #endif
365  }
366 
367 
368  template <int dim, int spacedim>
369  template <typename T>
370  void
372  const std::vector<T> &input,
373  std::vector<T> & buffer,
374  const std::function<void(const ArrayView<const T> &, const CellData &)>
375  &evaluation_function) const
376  {
377 #ifndef DEAL_II_WITH_MPI
378  Assert(false, ExcNeedsMPI());
379  (void)input;
380  (void)buffer;
381  (void)evaluation_function;
382 #else
383  static CollectiveMutex mutex;
384  CollectiveMutex::ScopedLock lock(mutex, tria->get_communicator());
385 
386  const auto &ptr = this->get_point_ptrs();
387 
388  std::map<unsigned int, std::vector<T>> temp_recv_map;
389 
390  for (unsigned int i = 0; i < recv_ranks.size(); ++i)
391  temp_recv_map[recv_ranks[i]].resize(recv_ptrs[i + 1] - recv_ptrs[i]);
392 
393  const unsigned int my_rank =
395 
396 # ifdef DEBUG
397  {
398  unsigned int i = 0;
399 
400  for (auto &j : temp_recv_map)
401  i += j.second.size();
402 
403  AssertDimension(recv_permutation.size(), i);
404  }
405 # endif
406 
407  {
408  // duplicate data to be able to sort it more easily in the next step
409  std::vector<T> buffer_(ptr.back());
410  for (unsigned int i = 0, c = 0; i < ptr.size() - 1; ++i)
411  {
412  const auto n_entries = ptr[i + 1] - ptr[i];
413 
414  for (unsigned int j = 0; j < n_entries; ++j, ++c)
415  buffer_[c] = input[i];
416  }
417 
418  // sort data according to the ranks
419  auto it = recv_permutation.begin();
420  for (auto &j : temp_recv_map)
421  for (auto &i : j.second)
422  {
423  i = buffer_[*it];
424  it++;
425  }
426  }
427 
428  // buffer.resize(point_ptrs.back());
429  buffer.resize(send_permutation.size() * 2);
430  ArrayView<T> buffer_1(buffer.data(), buffer.size() / 2);
431  ArrayView<T> buffer_2(buffer.data() + buffer.size() / 2,
432  buffer.size() / 2);
433 
434  // process remote quadrature points and send them away
435  std::map<unsigned int, std::vector<char>> temp_map;
436 
437  std::vector<MPI_Request> requests;
438  requests.reserve(recv_ranks.size());
439 
440  for (const auto recv_rank : recv_ranks)
441  {
442  if (recv_rank == my_rank)
443  continue;
444 
445  temp_map[recv_rank] =
446  Utilities::pack(temp_recv_map[recv_rank], false);
447 
448  auto &buffer_send = temp_map[recv_rank];
449 
450  requests.push_back(MPI_Request());
451 
452  MPI_Isend(buffer_send.data(),
453  buffer_send.size(),
454  MPI_CHAR,
455  recv_rank,
457  tria->get_communicator(),
458  &requests.back());
459  }
460 
461  for (unsigned int i = 0; i < send_ranks.size(); ++i)
462  {
463  if (send_ranks[i] == my_rank)
464  {
465  const auto &buffer_send = temp_recv_map[send_ranks[i]];
466  // process locally-owned values
467  const unsigned int j = std::distance(send_ranks.begin(),
468  std::find(send_ranks.begin(),
469  send_ranks.end(),
470  my_rank));
471 
472  AssertDimension(buffer_send.size(),
473  send_ptrs[j + 1] - send_ptrs[j]);
474 
475  for (unsigned int i = send_ptrs[j], c = 0; i < send_ptrs[j + 1];
476  ++i, ++c)
477  buffer_1[i] = buffer_send[c];
478 
479  continue;
480  }
481 
482  MPI_Status status;
483  MPI_Probe(MPI_ANY_SOURCE,
485  tria->get_communicator(),
486  &status);
487 
488  int message_length;
489  MPI_Get_count(&status, MPI_CHAR, &message_length);
490 
491  std::vector<char> recv_buffer(message_length);
492 
493  MPI_Recv(recv_buffer.data(),
494  recv_buffer.size(),
495  MPI_CHAR,
496  status.MPI_SOURCE,
498  tria->get_communicator(),
499  MPI_STATUS_IGNORE);
500 
501 
502  const auto recv_buffer_unpacked =
503  Utilities::unpack<std::vector<T>>(recv_buffer, false);
504 
505  auto ptr =
506  std::find(send_ranks.begin(), send_ranks.end(), status.MPI_SOURCE);
507 
508  Assert(ptr != send_ranks.end(), ExcNotImplemented());
509 
510  const unsigned int j = std::distance(send_ranks.begin(), ptr);
511 
512  AssertDimension(recv_buffer_unpacked.size(),
513  send_ptrs[j + 1] - send_ptrs[j]);
514 
515  for (unsigned int i = send_ptrs[j], c = 0; i < send_ptrs[j + 1];
516  ++i, ++c)
517  {
518  AssertIndexRange(i, buffer_1.size());
519  AssertIndexRange(c, recv_buffer_unpacked.size());
520  buffer_1[i] = recv_buffer_unpacked[c];
521  }
522  }
523 
524  MPI_Waitall(requests.size(), requests.data(), MPI_STATUSES_IGNORE);
525 
526  // sort for easy access during function call
527  for (unsigned int i = 0; i < send_permutation.size(); ++i)
528  buffer_2[i] = buffer_1[send_permutation[i]];
529 
530  // evaluate function at points
531  evaluation_function(buffer_2, cell_data);
532 #endif
533  }
534 
535  } // end of namespace MPI
536 } // end of namespace Utilities
537 
538 
540 
541 #endif
iterator begin() const
Definition: array_view.h:583
std::size_t size() const
Definition: array_view.h:574
virtual MPI_Comm get_communicator() const
void evaluate_and_process(std::vector< T > &output, std::vector< T > &buffer, const std::function< void(const ArrayView< T > &, const CellData &)> &evaluation_function) const
const Triangulation< dim, spacedim > & get_triangulation() const
SmartPointer< const Mapping< dim, spacedim > > mapping
void process_and_evaluate(const std::vector< T > &input, std::vector< T > &buffer, const std::function< void(const ArrayView< const T > &, const CellData &)> &evaluation_function) const
const std::vector< unsigned int > & get_point_ptrs() const
RemotePointEvaluation(const double tolerance=1e-6, const bool enforce_unique_mapping=false)
const Mapping< dim, spacedim > & get_mapping() const
SmartPointer< const Triangulation< dim, spacedim > > tria
void reinit(const std::vector< Point< spacedim >> &points, const Triangulation< dim, spacedim > &tria, const Mapping< dim, spacedim > &mapping)
#define DEAL_II_NAMESPACE_OPEN
Definition: config.h:396
#define DEAL_II_NAMESPACE_CLOSE
Definition: config.h:397
static ::ExceptionBase & ExcNeedsMPI()
#define Assert(cond, exc)
Definition: exceptions.h:1465
static ::ExceptionBase & ExcNotImplemented()
#define AssertDimension(dim1, dim2)
Definition: exceptions.h:1622
#define AssertIndexRange(index, range)
Definition: exceptions.h:1690
SymmetricTensor< 2, dim, Number > e(const Tensor< 2, dim, Number > &F)
unsigned int this_mpi_process(const MPI_Comm &mpi_communicator)
Definition: mpi.cc:128
size_t pack(const T &object, std::vector< char > &dest_buffer, const bool allow_compression=true)
Definition: utilities.h:1218