Reference documentation for deal.II version 9.3.3
\(\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
29namespace 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
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;
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;
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
void reinit(const std::vector< Point< spacedim > > &points, const Triangulation< dim, spacedim > &tria, const Mapping< dim, spacedim > &mapping)
SmartPointer< const Triangulation< dim, spacedim > > tria
#define DEAL_II_NAMESPACE_OPEN
Definition: config.h:402
#define DEAL_II_NAMESPACE_CLOSE
Definition: config.h:403
static ::ExceptionBase & ExcNotImplemented()
static ::ExceptionBase & ExcNeedsMPI()
#define Assert(cond, exc)
Definition: exceptions.h:1465
#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