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\}}\)
vector_data_exchange.cc
Go to the documentation of this file.
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 2020 - 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 
17 #include <deal.II/base/mpi.h>
18 #include <deal.II/base/mpi.templates.h>
21 #include <deal.II/base/timer.h>
22 
24 
25 #ifdef DEAL_II_WITH_64BIT_INDICES
26 # include <deal.II/base/mpi_consensus_algorithms.templates.h>
27 #endif
28 
29 #include <map>
30 #include <vector>
31 
32 
34 
35 namespace internal
36 {
37  namespace MatrixFreeFunctions
38  {
39  namespace VectorDataExchange
40  {
42  const std::shared_ptr<const Utilities::MPI::Partitioner> &partitioner)
43  : partitioner(partitioner)
44  {}
45 
46 
47 
48  unsigned int
50  {
51  return partitioner->locally_owned_size();
52  }
53 
54 
55 
56  unsigned int
58  {
59  return partitioner->n_ghost_indices();
60  }
61 
62 
63 
64  unsigned int
66  {
67  return partitioner->n_import_indices();
68  }
69 
70 
71 
72  unsigned int
74  {
75  return 0;
76  }
77 
78 
79 
82  {
83  return partitioner->size();
84  }
85 
86 
87 
88  void
90  const unsigned int communication_channel,
91  const ArrayView<const double> & locally_owned_array,
92  const std::vector<ArrayView<const double>> &shared_arrays,
93  const ArrayView<double> & ghost_array,
94  const ArrayView<double> & temporary_storage,
95  std::vector<MPI_Request> & requests) const
96  {
97  (void)shared_arrays;
98 #ifndef DEAL_II_WITH_MPI
99  (void)communication_channel;
100  (void)locally_owned_array;
101  (void)ghost_array;
102  (void)temporary_storage;
103  (void)requests;
104 #else
105  partitioner->export_to_ghosted_array_start(communication_channel,
106  locally_owned_array,
107  temporary_storage,
108  ghost_array,
109  requests);
110 #endif
111  }
112 
113 
114 
115  void
117  const ArrayView<const double> & locally_owned_array,
118  const std::vector<ArrayView<const double>> &shared_arrays,
119  const ArrayView<double> & ghost_array,
120  std::vector<MPI_Request> & requests) const
121  {
122  (void)locally_owned_array;
123  (void)shared_arrays;
124 #ifndef DEAL_II_WITH_MPI
125  (void)ghost_array;
126  (void)requests;
127 #else
128  partitioner->export_to_ghosted_array_finish(ghost_array, requests);
129 #endif
130  }
131 
132 
133 
134  void
136  const VectorOperation::values vector_operation,
137  const unsigned int communication_channel,
138  const ArrayView<const double> & locally_owned_array,
139  const std::vector<ArrayView<const double>> &shared_arrays,
140  const ArrayView<double> & ghost_array,
141  const ArrayView<double> & temporary_storage,
142  std::vector<MPI_Request> & requests) const
143  {
144  (void)locally_owned_array;
145  (void)shared_arrays;
146 #ifndef DEAL_II_WITH_MPI
147  (void)vector_operation;
148  (void)communication_channel;
149  (void)ghost_array;
150  (void)temporary_storage;
151  (void)requests;
152 #else
153  partitioner->import_from_ghosted_array_start(vector_operation,
154  communication_channel,
155  ghost_array,
156  temporary_storage,
157  requests);
158 #endif
159  }
160 
161 
162 
163  void
165  const VectorOperation::values vector_operation,
166  const ArrayView<double> & locally_owned_storage,
167  const std::vector<ArrayView<const double>> &shared_arrays,
168  const ArrayView<double> & ghost_array,
169  const ArrayView<const double> & temporary_storage,
170  std::vector<MPI_Request> & requests) const
171  {
172  (void)shared_arrays;
173 #ifndef DEAL_II_WITH_MPI
174  (void)vector_operation;
175  (void)locally_owned_storage;
176  (void)ghost_array;
177  (void)temporary_storage;
178  (void)requests;
179 #else
180  partitioner->import_from_ghosted_array_finish(vector_operation,
181  temporary_storage,
182  locally_owned_storage,
183  ghost_array,
184  requests);
185 #endif
186  }
187 
188 
189 
190  void
192  const ArrayView<double> &ghost_array) const
193  {
194  reset_ghost_values_impl(ghost_array);
195  }
196 
197 
198 
199  void
201  const unsigned int communication_channel,
202  const ArrayView<const float> & locally_owned_array,
203  const std::vector<ArrayView<const float>> &shared_arrays,
204  const ArrayView<float> & ghost_array,
205  const ArrayView<float> & temporary_storage,
206  std::vector<MPI_Request> & requests) const
207  {
208  (void)shared_arrays;
209 #ifndef DEAL_II_WITH_MPI
210  (void)communication_channel;
211  (void)locally_owned_array;
212  (void)ghost_array;
213  (void)temporary_storage;
214  (void)requests;
215 #else
216  partitioner->export_to_ghosted_array_start(communication_channel,
217  locally_owned_array,
218  temporary_storage,
219  ghost_array,
220  requests);
221 #endif
222  }
223 
224 
225 
226  void
228  const ArrayView<const float> & locally_owned_array,
229  const std::vector<ArrayView<const float>> &shared_arrays,
230  const ArrayView<float> & ghost_array,
231  std::vector<MPI_Request> & requests) const
232  {
233  (void)locally_owned_array;
234  (void)shared_arrays;
235 #ifndef DEAL_II_WITH_MPI
236  (void)ghost_array;
237  (void)requests;
238 #else
239  partitioner->export_to_ghosted_array_finish(ghost_array, requests);
240 #endif
241  }
242 
243 
244 
245  void
247  const VectorOperation::values vector_operation,
248  const unsigned int communication_channel,
249  const ArrayView<const float> & locally_owned_array,
250  const std::vector<ArrayView<const float>> &shared_arrays,
251  const ArrayView<float> & ghost_array,
252  const ArrayView<float> & temporary_storage,
253  std::vector<MPI_Request> & requests) const
254  {
255  (void)locally_owned_array;
256  (void)shared_arrays;
257 #ifndef DEAL_II_WITH_MPI
258  (void)vector_operation;
259  (void)communication_channel;
260  (void)ghost_array;
261  (void)temporary_storage;
262  (void)requests;
263 #else
264  partitioner->import_from_ghosted_array_start(vector_operation,
265  communication_channel,
266  ghost_array,
267  temporary_storage,
268  requests);
269 #endif
270  }
271 
272 
273 
274  void
276  const VectorOperation::values vector_operation,
277  const ArrayView<float> & locally_owned_storage,
278  const std::vector<ArrayView<const float>> &shared_arrays,
279  const ArrayView<float> & ghost_array,
280  const ArrayView<const float> & temporary_storage,
281  std::vector<MPI_Request> & requests) const
282  {
283  (void)shared_arrays;
284 #ifndef DEAL_II_WITH_MPI
285  (void)vector_operation;
286  (void)locally_owned_storage;
287  (void)ghost_array;
288  (void)temporary_storage;
289  (void)requests;
290 #else
291  partitioner->import_from_ghosted_array_finish(vector_operation,
292  temporary_storage,
293  locally_owned_storage,
294  ghost_array,
295  requests);
296 #endif
297  }
298 
299 
300 
301  void
303  const ArrayView<float> &ghost_array) const
304  {
305  reset_ghost_values_impl(ghost_array);
306  }
307 
308 
309 
310  template <typename Number>
311  void
313  const ArrayView<Number> &ghost_array) const
314  {
315  for (const auto &my_ghosts :
316  partitioner->ghost_indices_within_larger_ghost_set())
317  for (unsigned int j = my_ghosts.first; j < my_ghosts.second; ++j)
318  ghost_array[j] = 0.;
319  }
320 
321 
322 
323  namespace internal
324  {
325  std::pair<std::vector<unsigned int>,
326  std::vector<std::pair<unsigned int, unsigned int>>>
328  const std::vector<unsigned int> &sm_export_ptr,
329  const std::vector<unsigned int> &sm_export_indices)
330  {
331  std::vector<unsigned int> recv_ptr = {0};
332  std::vector<unsigned int> recv_indices;
333  std::vector<unsigned int> recv_len;
334 
335  for (unsigned int i = 0; i + 1 < sm_export_ptr.size(); i++)
336  {
337  if (sm_export_ptr[i] != sm_export_ptr[i + 1])
338  {
339  recv_indices.push_back(sm_export_indices[sm_export_ptr[i]]);
340  recv_len.push_back(1);
341 
342  for (unsigned int j = sm_export_ptr[i] + 1;
343  j < sm_export_ptr[i + 1];
344  j++)
345  if (recv_indices.back() + recv_len.back() !=
346  sm_export_indices[j])
347  {
348  recv_indices.push_back(sm_export_indices[j]);
349  recv_len.push_back(1);
350  }
351  else
352  recv_len.back()++;
353  }
354  recv_ptr.push_back(recv_indices.size());
355  }
356 
357  std::pair<std::vector<unsigned int>,
358  std::vector<std::pair<unsigned int, unsigned int>>>
359  result;
360 
361  result.first = recv_ptr;
362 
363  for (unsigned int i = 0; i < recv_indices.size(); ++i)
364  result.second.emplace_back(recv_indices[i], recv_len[i]);
365 
366  return result;
367  }
368 
369  } // namespace internal
370 
371 
372 
374  const std::shared_ptr<const Utilities::MPI::Partitioner> &partitioner,
375  const MPI_Comm &communicator_sm)
376  : comm(partitioner->get_mpi_communicator())
377  , comm_sm(communicator_sm)
378  , n_local_elements(partitioner->locally_owned_range().n_elements())
379  , n_ghost_elements(partitioner->ghost_indices().n_elements())
380  , n_global_elements(partitioner->locally_owned_range().size())
381  {
382 #ifndef DEAL_II_WITH_MPI
383  Assert(false, ExcNeedsMPI());
384 #else
385  if (Utilities::MPI::job_supports_mpi() == false)
386  return; // nothing to do in serial case
387 
388  const auto &is_locally_owned = partitioner->locally_owned_range();
389  const auto &is_locally_ghost = partitioner->ghost_indices();
390  const auto &ghost_indices_within_larger_ghost_set =
391  partitioner->ghost_indices_within_larger_ghost_set();
392 
393  // temporal data strucutures
394  std::vector<unsigned int> n_ghost_indices_in_larger_set_by_remote_rank;
395 
396  std::vector<std::array<unsigned int, 3>> ghost_targets_data;
397 
398  std::vector<std::array<unsigned int, 3>> import_targets_data;
399 
400  std::vector<unsigned int> sm_ghost_ranks;
401 
402  std::vector<unsigned int> sm_import_ranks;
403 
404  // temporary uncompressed data structures for ghost_indices_subset_data
405  std::vector<unsigned int> ghost_indices_subset_data_ptr = {0};
406  std::vector<unsigned int> ghost_indices_subset_data_indices;
407 
408  // ... for import_indices_data
409  std::vector<unsigned int> import_indices_data_ptr = {0};
410  std::vector<unsigned int> import_indices_data_indices;
411 
412  // ... for sm_export_data
413  std::vector<unsigned int> sm_export_data_ptr = {0};
414  std::vector<unsigned int> sm_export_data_indices;
415 
416  // ... for sm_export_data_this
417  std::vector<unsigned int> sm_export_data_this_ptr = {0};
418  std::vector<unsigned int> sm_export_data_this_indices;
419 
420  // ... for sm_import_data
421  std::vector<unsigned int> sm_import_data_ptr = {};
422  std::vector<unsigned int> sm_import_data_indices;
423 
424  // ... for sm_import_data_this
425  std::vector<unsigned int> sm_import_data_this_ptr = {0};
426  std::vector<unsigned int> sm_import_data_this_indices;
427 
428  // collect ranks of processes of shared-memory domain
429  const auto sm_ranks =
431 
432  // determine owners of ghost indices and determine requesters
433  std::vector<unsigned int> owning_ranks_of_ghosts(
434  is_locally_ghost.n_elements());
435 
437  process(is_locally_owned,
438  is_locally_ghost,
439  comm,
440  owning_ranks_of_ghosts,
441  /*track_index_requests = */ true);
442 
444  std::pair<types::global_dof_index, types::global_dof_index>,
445  unsigned int>
446  consensus_algorithm(process, comm);
447  consensus_algorithm.run();
448 
449  // decompress ghost_indices_within_larger_ghost_set for simpler
450  // data access during setup
451  std::vector<unsigned int> shifts_indices;
452  for (const auto &pair : ghost_indices_within_larger_ghost_set)
453  for (unsigned int k = pair.first; k < pair.second; ++k)
454  shifts_indices.push_back(k);
455 
456  // process ghost indices
457  {
458  // collect ghost indices according to owning rank
459  std::map<unsigned int, std::vector<types::global_dof_index>>
460  rank_to_local_indices;
461 
462  for (unsigned int i = 0; i < owning_ranks_of_ghosts.size(); i++)
463  rank_to_local_indices[owning_ranks_of_ghosts[i]].push_back(i);
464 
465  unsigned int compressed_offset = 0;
466 
467  for (const auto &rank_and_local_indices : rank_to_local_indices)
468  {
469  const auto sm_ranks_ptr = std::find(sm_ranks.begin(),
470  sm_ranks.end(),
471  rank_and_local_indices.first);
472 
473  if (sm_ranks_ptr == sm_ranks.end()) // remote process
474  {
475  ghost_targets_data.emplace_back(std::array<unsigned int, 3>{{
476  rank_and_local_indices.first, // rank
477  shifts_indices[compressed_offset], // offset
478  static_cast<unsigned int>(
479  rank_and_local_indices.second.size()) // length
480  }});
481 
482  for (unsigned int i = 0;
483  i < rank_and_local_indices.second.size();
484  ++i)
485  ghost_indices_subset_data_indices.push_back(
486  shifts_indices[i + compressed_offset]);
487 
488  ghost_indices_subset_data_ptr.push_back(
489  ghost_indices_subset_data_indices.size());
490 
491  ghost_indices_subset_data.first.push_back(compressed_offset);
492 
493  unsigned int i =
495 
497  (shifts_indices[ghost_indices_subset_data.first[i] +
498  (ghost_targets_data[i][2] - 1)] -
499  shifts_indices[ghost_indices_subset_data.first[i]]) +
500  1);
501  }
502  else // shared process
503  {
504  sm_ghost_ranks.push_back(
505  std::distance(sm_ranks.begin(), sm_ranks_ptr));
506 
507  sm_export_data_ptr.push_back(
508  sm_export_data_ptr.back() +
509  rank_and_local_indices.second.size());
510 
511  for (unsigned int i = compressed_offset;
512  i <
513  rank_and_local_indices.second.size() + compressed_offset;
514  ++i)
515  sm_export_data_this_indices.push_back(
516  shifts_indices[i] + is_locally_owned.n_elements());
517 
518  sm_export_data_this_ptr.push_back(
519  sm_export_data_this_indices.size());
520  }
521  compressed_offset += rank_and_local_indices.second.size();
522  }
523 
524  sm_export_data_indices.resize(sm_export_data_ptr.back());
525  }
526 
527  // process requesters
528  {
529  const auto rank_to_global_indices = process.get_requesters();
530 
531  for (const auto &rank_and_global_indices : rank_to_global_indices)
532  {
533  const auto sm_ranks_ptr =
534  std::find(sm_ranks.begin(),
535  sm_ranks.end(),
536  rank_and_global_indices.first);
537 
538  if (sm_ranks_ptr == sm_ranks.end()) // remote process
539  {
540  import_targets_data.emplace_back(std::array<unsigned int, 3>{{
541  rank_and_global_indices.first, // rank
542  static_cast<unsigned int>(
543  import_indices_data_indices.size()), // offset
544  static_cast<unsigned int>(
545  rank_and_global_indices.second.n_elements()) // length
546  }});
547 
548  for (const auto i : rank_and_global_indices.second)
549  import_indices_data_indices.push_back(
550  is_locally_owned.index_within_set(i));
551 
552  import_indices_data_ptr.push_back(
553  import_indices_data_indices.size());
554  }
555  else // shared process
556  {
557  sm_import_ranks.push_back(
558  std::distance(sm_ranks.begin(), sm_ranks_ptr));
559 
560  for (const auto i : rank_and_global_indices.second)
561  sm_import_data_this_indices.push_back(
562  is_locally_owned.index_within_set(i));
563 
564  sm_import_data_this_ptr.push_back(
565  sm_import_data_this_indices.size());
566  }
567  }
568 
569  sm_import_data_ptr = sm_import_data_this_ptr;
570  sm_import_data_indices.resize(sm_import_data_this_ptr.back());
571  }
572 
573  // send sm_export_data_this to sm-neighbor -> sm_import_data
574  {
575  std::vector<MPI_Request> requests(sm_ghost_ranks.size() +
576  sm_import_ranks.size());
577 
578  for (unsigned int i = 0; i < sm_ghost_ranks.size(); i++)
579  {
580  const int ierr = MPI_Isend(sm_export_data_this_indices.data() +
581  sm_export_data_this_ptr[i],
582  sm_export_data_this_ptr[i + 1] -
583  sm_export_data_this_ptr[i],
584  MPI_UNSIGNED,
585  sm_ghost_ranks[i],
586  4,
587  comm_sm,
588  requests.data() + i);
589  AssertThrowMPI(ierr);
590  }
591 
592  for (unsigned int i = 0; i < sm_import_ranks.size(); i++)
593  {
594  const int ierr =
595  MPI_Irecv(sm_import_data_indices.data() + sm_import_data_ptr[i],
596  sm_import_data_ptr[i + 1] - sm_import_data_ptr[i],
597  MPI_UNSIGNED,
598  sm_import_ranks[i],
599  4,
600  comm_sm,
601  requests.data() + sm_ghost_ranks.size() + i);
602  AssertThrowMPI(ierr);
603  }
604 
605  const int ierr =
606  MPI_Waitall(requests.size(), requests.data(), MPI_STATUSES_IGNORE);
607  AssertThrowMPI(ierr);
608  }
609 
610  // send sm_import_data_this to sm-neighbor -> sm_export_data_indices
611  {
612  std::vector<MPI_Request> requests(sm_import_ranks.size() +
613  sm_ghost_ranks.size());
614 
615  for (unsigned int i = 0; i < sm_import_ranks.size(); i++)
616  {
617  const int ierr = MPI_Isend(sm_import_data_this_indices.data() +
618  sm_import_data_this_ptr[i],
619  sm_import_data_this_ptr[i + 1] -
620  sm_import_data_this_ptr[i],
621  MPI_UNSIGNED,
622  sm_import_ranks[i],
623  2,
624  comm_sm,
625  requests.data() + i);
626  AssertThrowMPI(ierr);
627  }
628 
629  for (unsigned int i = 0; i < sm_ghost_ranks.size(); i++)
630  {
631  const int ierr =
632  MPI_Irecv(sm_export_data_indices.data() + sm_export_data_ptr[i],
633  sm_export_data_ptr[i + 1] - sm_export_data_ptr[i],
634  MPI_UNSIGNED,
635  sm_ghost_ranks[i],
636  2,
637  comm_sm,
638  requests.data() + sm_import_ranks.size() + i);
639  AssertThrowMPI(ierr);
640  }
641 
642  const int ierr =
643  MPI_Waitall(requests.size(), requests.data(), MPI_STATUSES_IGNORE);
644  AssertThrowMPI(ierr);
645  }
646 
647  // store data structures and, if needed, compress them
648  this->n_ghost_indices_in_larger_set_by_remote_rank =
650 
653  ghost_indices_subset_data_ptr, ghost_indices_subset_data_indices);
654 
655  this->ghost_targets_data = ghost_targets_data;
656 
657  this->import_targets_data = import_targets_data;
658 
659  this->import_indices_data =
660  internal::compress_to_contiguous_ranges(import_indices_data_ptr,
661  import_indices_data_indices);
662 
663  this->sm_ghost_ranks = sm_ghost_ranks;
664 
665  this->sm_export_data =
666  internal::compress_to_contiguous_ranges(sm_export_data_ptr,
667  sm_export_data_indices);
668 
669  this->sm_export_data_this =
670  internal::compress_to_contiguous_ranges(sm_export_data_this_ptr,
671  sm_export_data_this_indices);
672 
673  this->sm_import_ranks = sm_import_ranks;
674 
675  this->sm_import_data =
676  internal::compress_to_contiguous_ranges(sm_import_data_ptr,
677  sm_import_data_indices);
678 
679  this->sm_import_data_this =
680  internal::compress_to_contiguous_ranges(sm_import_data_this_ptr,
681  sm_import_data_this_indices);
682 
683 #endif
684  }
685 
686 
687 
688  void
690  const unsigned int communication_channel,
691  const ArrayView<const double> & locally_owned_array,
692  const std::vector<ArrayView<const double>> &shared_arrays,
693  const ArrayView<double> & ghost_array,
694  const ArrayView<double> & temporary_storage,
695  std::vector<MPI_Request> & requests) const
696  {
697  export_to_ghosted_array_start_impl(communication_channel,
698  locally_owned_array,
699  shared_arrays,
700  ghost_array,
701  temporary_storage,
702  requests);
703  }
704 
705 
706 
707  void
709  const ArrayView<const double> & locally_owned_array,
710  const std::vector<ArrayView<const double>> &shared_arrays,
711  const ArrayView<double> & ghost_array,
712  std::vector<MPI_Request> & requests) const
713  {
714  export_to_ghosted_array_finish_impl(locally_owned_array,
715  shared_arrays,
716  ghost_array,
717  requests);
718  }
719 
720 
721 
722  void
724  const VectorOperation::values vector_operation,
725  const unsigned int communication_channel,
726  const ArrayView<const double> & locally_owned_array,
727  const std::vector<ArrayView<const double>> &shared_arrays,
728  const ArrayView<double> & ghost_array,
729  const ArrayView<double> & temporary_storage,
730  std::vector<MPI_Request> & requests) const
731  {
732  import_from_ghosted_array_start_impl(vector_operation,
733  communication_channel,
734  locally_owned_array,
735  shared_arrays,
736  ghost_array,
737  temporary_storage,
738  requests);
739  }
740 
741 
742 
743  void
745  const VectorOperation::values vector_operation,
746  const ArrayView<double> & locally_owned_storage,
747  const std::vector<ArrayView<const double>> &shared_arrays,
748  const ArrayView<double> & ghost_array,
749  const ArrayView<const double> & temporary_storage,
750  std::vector<MPI_Request> & requests) const
751  {
752  import_from_ghosted_array_finish_impl(vector_operation,
753  locally_owned_storage,
754  shared_arrays,
755  ghost_array,
756  temporary_storage,
757  requests);
758  }
759 
760 
761 
762  void
764  const unsigned int communication_channel,
765  const ArrayView<const float> & locally_owned_array,
766  const std::vector<ArrayView<const float>> &shared_arrays,
767  const ArrayView<float> & ghost_array,
768  const ArrayView<float> & temporary_storage,
769  std::vector<MPI_Request> & requests) const
770  {
771  export_to_ghosted_array_start_impl(communication_channel,
772  locally_owned_array,
773  shared_arrays,
774  ghost_array,
775  temporary_storage,
776  requests);
777  }
778 
779 
780 
781  void
783  const ArrayView<const float> & locally_owned_array,
784  const std::vector<ArrayView<const float>> &shared_arrays,
785  const ArrayView<float> & ghost_array,
786  std::vector<MPI_Request> & requests) const
787  {
788  export_to_ghosted_array_finish_impl(locally_owned_array,
789  shared_arrays,
790  ghost_array,
791  requests);
792  }
793 
794 
795 
796  void
798  const VectorOperation::values vector_operation,
799  const unsigned int communication_channel,
800  const ArrayView<const float> & locally_owned_array,
801  const std::vector<ArrayView<const float>> &shared_arrays,
802  const ArrayView<float> & ghost_array,
803  const ArrayView<float> & temporary_storage,
804  std::vector<MPI_Request> & requests) const
805  {
806  import_from_ghosted_array_start_impl(vector_operation,
807  communication_channel,
808  locally_owned_array,
809  shared_arrays,
810  ghost_array,
811  temporary_storage,
812  requests);
813  }
814 
815 
816 
817  void
819  const VectorOperation::values vector_operation,
820  const ArrayView<float> & locally_owned_storage,
821  const std::vector<ArrayView<const float>> &shared_arrays,
822  const ArrayView<float> & ghost_array,
823  const ArrayView<const float> & temporary_storage,
824  std::vector<MPI_Request> & requests) const
825  {
826  import_from_ghosted_array_finish_impl(vector_operation,
827  locally_owned_storage,
828  shared_arrays,
829  ghost_array,
830  temporary_storage,
831  requests);
832  }
833 
834 
835 
836  template <typename Number>
837  void
839  const unsigned int communication_channel,
840  const ArrayView<const Number> & data_this,
841  const std::vector<ArrayView<const Number>> &data_others,
842  const ArrayView<Number> & buffer,
843  const ArrayView<Number> & temporary_storage,
844  std::vector<MPI_Request> & requests) const
845  {
846 #ifndef DEAL_II_WITH_MPI
847  Assert(false, ExcNeedsMPI());
848 
849  (void)communication_channel;
850  (void)data_this;
851  (void)data_others;
852  (void)buffer;
853  (void)temporary_storage;
854  (void)requests;
855 #else
856  (void)data_others;
857 
858  requests.resize(sm_import_ranks.size() + sm_ghost_ranks.size() +
859  ghost_targets_data.size() + import_targets_data.size());
860 
861  int dummy;
862  // receive a signal that relevant sm neighbors are ready
863  for (unsigned int i = 0; i < sm_ghost_ranks.size(); i++)
864  {
865  const int ierr =
866  MPI_Irecv(&dummy,
867  0,
868  MPI_INT,
869  sm_ghost_ranks[i],
870  communication_channel + 0,
871  comm_sm,
872  requests.data() + sm_import_ranks.size() + i);
873  AssertThrowMPI(ierr);
874  }
875 
876  // signal to all relevant sm neighbors that this process is ready
877  for (unsigned int i = 0; i < sm_import_ranks.size(); i++)
878  {
879  const int ierr = MPI_Isend(&dummy,
880  0,
881  MPI_INT,
882  sm_import_ranks[i],
883  communication_channel + 0,
884  comm_sm,
885  requests.data() + i);
886  AssertThrowMPI(ierr);
887  }
888 
889  // receive data from remote processes
890  for (unsigned int i = 0; i < ghost_targets_data.size(); i++)
891  {
892  const unsigned int offset =
894  ghost_targets_data[i][2];
895 
896  const int ierr =
897  MPI_Irecv(buffer.data() + ghost_targets_data[i][1] + offset,
898  ghost_targets_data[i][2],
899  Utilities::MPI::internal::mpi_type_id(buffer.data()),
900  ghost_targets_data[i][0],
901  communication_channel + 1,
902  comm,
903  requests.data() + sm_import_ranks.size() +
904  sm_ghost_ranks.size() + i);
905  AssertThrowMPI(ierr);
906  }
907 
908  // send data to remote processes
909  for (unsigned int i = 0, k = 0; i < import_targets_data.size(); i++)
910  {
911  for (unsigned int j = import_indices_data.first[i];
912  j < import_indices_data.first[i + 1];
913  j++)
914  for (unsigned int l = 0; l < import_indices_data.second[j].second;
915  l++, k++)
916  temporary_storage[k] =
917  data_this[import_indices_data.second[j].first + l];
918 
919  // send data away
920  const int ierr =
921  MPI_Isend(temporary_storage.data() + import_targets_data[i][1],
922  import_targets_data[i][2],
923  Utilities::MPI::internal::mpi_type_id(data_this.data()),
924  import_targets_data[i][0],
925  communication_channel + 1,
926  comm,
927  requests.data() + sm_import_ranks.size() +
928  sm_ghost_ranks.size() + ghost_targets_data.size() +
929  i);
930  AssertThrowMPI(ierr);
931  }
932 #endif
933  }
934 
935 
936 
937  template <typename Number>
938  void
940  const ArrayView<const Number> & data_this,
941  const std::vector<ArrayView<const Number>> &data_others,
942  const ArrayView<Number> & ghost_array,
943  std::vector<MPI_Request> & requests) const
944  {
945  (void)data_this;
946 
947 #ifndef DEAL_II_WITH_MPI
948  Assert(false, ExcNeedsMPI());
949 
950  (void)data_others;
951  (void)ghost_array;
952  (void)requests;
953 #else
954 
955  AssertDimension(requests.size(),
956  sm_import_ranks.size() + sm_ghost_ranks.size() +
957  ghost_targets_data.size() +
958  import_targets_data.size());
959 
960  const auto split =
961  [&](const unsigned int i) -> std::pair<unsigned int, unsigned int> {
963  (sm_ghost_ranks.size() + ghost_targets_data.size()));
964 
965  if (i < sm_ghost_ranks.size())
966  return {0, i};
967  else
968  return {1, i - sm_ghost_ranks.size()};
969  };
970 
971  for (unsigned int c = 0;
972  c < sm_ghost_ranks.size() + ghost_targets_data.size();
973  c++)
974  {
975  int i;
976  const int ierr =
977  MPI_Waitany(sm_ghost_ranks.size() + ghost_targets_data.size(),
978  requests.data() + sm_import_ranks.size(),
979  &i,
980  MPI_STATUS_IGNORE);
981  AssertThrowMPI(ierr);
982 
983  const auto s = split(i);
984  i = s.second;
985 
986  if (s.first == 0)
987  {
988  const Number *DEAL_II_RESTRICT data_others_ptr =
989  data_others[sm_ghost_ranks[i]].data();
990  Number *DEAL_II_RESTRICT data_this_ptr = ghost_array.data();
991 
992  for (unsigned int lo = sm_export_data.first[i],
993  ko = sm_export_data_this.first[i],
994  li = 0,
995  ki = 0;
996  (lo < sm_export_data.first[i + 1]) &&
997  (ko < sm_export_data_this.first[i + 1]);)
998  {
999  for (; (li < sm_export_data.second[lo].second) &&
1000  (ki < sm_export_data_this.second[ko].second);
1001  ++li, ++ki)
1002  data_this_ptr[sm_export_data_this.second[ko].first + ki -
1003  n_local_elements] =
1004  data_others_ptr[sm_export_data.second[lo].first + li];
1005 
1006  if (li == sm_export_data.second[lo].second)
1007  {
1008  lo++; // increment outer counter
1009  li = 0; // reset inner counter
1010  }
1011 
1012  if (ki == sm_export_data_this.second[ko].second)
1013  {
1014  ko++; // increment outer counter
1015  ki = 0; // reset inner counter
1016  }
1017  }
1018  }
1019  else /*if(s.second == 1)*/
1020  {
1021  const unsigned int offset =
1023  ghost_targets_data[i][2];
1024 
1025  for (unsigned int c = 0,
1026  ko = ghost_indices_subset_data.first[i],
1027  ki = 0;
1028  c < ghost_targets_data[i][2];
1029  ++c)
1030  {
1031  AssertIndexRange(ko,
1032  ghost_indices_subset_data.second.size());
1033 
1034  const unsigned int idx_1 =
1035  ghost_indices_subset_data.second[ko].first + ki;
1036  const unsigned int idx_2 =
1037  ghost_targets_data[i][1] + c + offset;
1038 
1039  AssertIndexRange(idx_1, ghost_array.size());
1040  AssertIndexRange(idx_2, ghost_array.size());
1041 
1042  if (idx_1 == idx_2)
1043  {
1044  // noting to do
1045  }
1046  else if (idx_1 < idx_2)
1047  {
1048  ghost_array[idx_1] = ghost_array[idx_2];
1049  ghost_array[idx_2] = 0.0;
1050  }
1051  else
1052  {
1053  Assert(false, ExcNotImplemented());
1054  }
1055 
1056  ++ki;
1057 
1058  if (ki == ghost_indices_subset_data.second[ko].second)
1059  {
1060  ko++; // increment outer counter
1061  ki = 0; // reset inner counter
1062  }
1063  }
1064  }
1065  }
1066 
1067  const int ierr =
1068  MPI_Waitall(requests.size(), requests.data(), MPI_STATUSES_IGNORE);
1069  AssertThrowMPI(ierr);
1070 
1071 #endif
1072  }
1073 
1074 
1075 
1076  template <typename Number>
1077  void
1079  const VectorOperation::values operation,
1080  const unsigned int communication_channel,
1081  const ArrayView<const Number> & data_this,
1082  const std::vector<ArrayView<const Number>> &data_others,
1083  const ArrayView<Number> & buffer,
1084  const ArrayView<Number> & temporary_storage,
1085  std::vector<MPI_Request> & requests) const
1086  {
1087  (void)data_this;
1088 
1089 #ifndef DEAL_II_WITH_MPI
1090  Assert(false, ExcNeedsMPI());
1091 
1092  (void)operation;
1093  (void)communication_channel;
1094  (void)data_others;
1095  (void)buffer;
1096  (void)temporary_storage;
1097  (void)requests;
1098 #else
1099  // return;
1100 
1101  (void)data_others;
1102  (void)operation;
1103 
1104  Assert(operation == ::VectorOperation::add, ExcNotImplemented());
1105 
1106  requests.resize(sm_ghost_ranks.size() + sm_import_ranks.size() +
1107  ghost_targets_data.size() + import_targets_data.size());
1108 
1109  int dummy;
1110  for (unsigned int i = 0; i < sm_ghost_ranks.size(); i++)
1111  {
1112  const int ierr = MPI_Isend(&dummy,
1113  0,
1114  MPI_INT,
1115  sm_ghost_ranks[i],
1116  communication_channel + 1,
1117  comm_sm,
1118  requests.data() + i);
1119  AssertThrowMPI(ierr);
1120  }
1121 
1122  for (unsigned int i = 0; i < sm_import_ranks.size(); i++)
1123  {
1124  const int ierr =
1125  MPI_Irecv(&dummy,
1126  0,
1127  MPI_INT,
1128  sm_import_ranks[i],
1129  communication_channel + 1,
1130  comm_sm,
1131  requests.data() + sm_ghost_ranks.size() + i);
1132  AssertThrowMPI(ierr);
1133  }
1134 
1135  for (unsigned int i = 0; i < ghost_targets_data.size(); i++)
1136  {
1137  for (unsigned int c = 0,
1138  ko = ghost_indices_subset_data.first[i],
1139  ki = 0;
1140  c < ghost_targets_data[i][2];
1141  ++c)
1142  {
1143  AssertIndexRange(ko, ghost_indices_subset_data.second.size());
1144 
1145  const unsigned int idx_1 =
1146  ghost_indices_subset_data.second[ko].first + ki;
1147  const unsigned int idx_2 = ghost_targets_data[i][1] + c;
1148 
1149  AssertIndexRange(idx_1, buffer.size());
1150  AssertIndexRange(idx_2, buffer.size());
1151 
1152  if (idx_1 == idx_2)
1153  {
1154  // nothing to do
1155  }
1156  else if (idx_2 < idx_1)
1157  {
1158  buffer[idx_2] = buffer[idx_1];
1159  buffer[idx_1] = 0.0;
1160  }
1161  else
1162  {
1163  Assert(false, ExcNotImplemented());
1164  }
1165 
1166  if (++ki == ghost_indices_subset_data.second[ko].second)
1167  {
1168  ko++; // increment outer counter
1169  ki = 0; // reset inner counter
1170  }
1171  }
1172 
1173  const int ierr =
1174  MPI_Isend(buffer.data() + ghost_targets_data[i][1],
1175  ghost_targets_data[i][2],
1176  Utilities::MPI::internal::mpi_type_id(buffer.data()),
1177  ghost_targets_data[i][0],
1178  communication_channel + 0,
1179  comm,
1180  requests.data() + sm_ghost_ranks.size() +
1181  sm_import_ranks.size() + i);
1182  AssertThrowMPI(ierr);
1183  }
1184 
1185  for (unsigned int i = 0; i < import_targets_data.size(); i++)
1186  {
1187  const int ierr = MPI_Irecv(
1188  temporary_storage.data() + import_targets_data[i][1],
1189  import_targets_data[i][2],
1190  Utilities::MPI::internal::mpi_type_id(temporary_storage.data()),
1191  import_targets_data[i][0],
1192  communication_channel + 0,
1193  comm,
1194  requests.data() + sm_ghost_ranks.size() + sm_import_ranks.size() +
1195  ghost_targets_data.size() + i);
1196  AssertThrowMPI(ierr);
1197  }
1198 #endif
1199  }
1200 
1201 
1202 
1203  template <typename Number>
1204  void
1206  const VectorOperation::values operation,
1207  const ArrayView<Number> & data_this,
1208  const std::vector<ArrayView<const Number>> &data_others,
1209  const ArrayView<Number> & buffer,
1210  const ArrayView<const Number> & temporary_storage,
1211  std::vector<MPI_Request> & requests) const
1212  {
1213 #ifndef DEAL_II_WITH_MPI
1214  Assert(false, ExcNeedsMPI());
1215 
1216  (void)operation;
1217  (void)data_this;
1218  (void)data_others;
1219  (void)buffer;
1220  (void)temporary_storage;
1221  (void)requests;
1222 #else
1223 
1224  (void)operation;
1225 
1226  Assert(operation == ::VectorOperation::add, ExcNotImplemented());
1227 
1228  AssertDimension(requests.size(),
1229  sm_ghost_ranks.size() + sm_import_ranks.size() +
1230  ghost_targets_data.size() +
1231  import_targets_data.size());
1232 
1233  const auto split =
1234  [&](const unsigned int i) -> std::pair<unsigned int, unsigned int> {
1235  AssertIndexRange(i,
1236  (sm_import_ranks.size() + ghost_targets_data.size() +
1237  import_targets_data.size()));
1238 
1239  if (i < sm_import_ranks.size())
1240  return {0, i};
1241  else if (i < (sm_import_ranks.size() + ghost_targets_data.size()))
1242  return {2, i - sm_import_ranks.size()};
1243  else
1244  return {1, i - sm_import_ranks.size() - ghost_targets_data.size()};
1245  };
1246 
1247  for (unsigned int c = 0;
1248  c < sm_import_ranks.size() + import_targets_data.size() +
1249  ghost_targets_data.size();
1250  c++)
1251  {
1252  int i;
1253  const int ierr =
1254  MPI_Waitany(sm_import_ranks.size() + import_targets_data.size() +
1255  ghost_targets_data.size(),
1256  requests.data() + sm_ghost_ranks.size(),
1257  &i,
1258  MPI_STATUS_IGNORE);
1259  AssertThrowMPI(ierr);
1260 
1261  const auto &s = split(i);
1262  i = s.second;
1263 
1264  if (s.first == 0)
1265  {
1266  Number *DEAL_II_RESTRICT data_others_ptr =
1267  const_cast<Number *>(data_others[sm_import_ranks[i]].data());
1268  Number *DEAL_II_RESTRICT data_this_ptr = data_this.data();
1269 
1270  for (unsigned int lo = sm_import_data_this.first[i],
1271  ko = sm_import_data.first[i],
1272  li = 0,
1273  ki = 0;
1274  (lo < sm_import_data_this.first[i + 1]) &&
1275  (ko < sm_import_data.first[i + 1]);)
1276  {
1277  for (; (li < sm_import_data_this.second[lo].second) &&
1278  (ki < sm_import_data.second[ko].second);
1279  ++li, ++ki)
1280  {
1281  data_this_ptr[sm_import_data_this.second[lo].first +
1282  li] +=
1283  data_others_ptr[sm_import_data.second[ko].first + ki];
1284  data_others_ptr[sm_import_data.second[ko].first + ki] =
1285  0.0;
1286  }
1287 
1288  if (li == sm_import_data_this.second[lo].second)
1289  {
1290  lo++; // increment outer counter
1291  li = 0; // reset inner counter
1292  }
1293  if (ki == sm_import_data.second[ko].second)
1294  {
1295  ko++; // increment outer counter
1296  ki = 0; // reset inner counter
1297  }
1298  }
1299  }
1300  else if (s.first == 1)
1301  {
1302  for (unsigned int j = import_indices_data.first[i],
1303  k = import_targets_data[i][1];
1304  j < import_indices_data.first[i + 1];
1305  j++)
1306  for (unsigned int l = 0;
1307  l < import_indices_data.second[j].second;
1308  l++)
1309  data_this[import_indices_data.second[j].first + l] +=
1310  temporary_storage[k++];
1311  }
1312  else /*if (s.first == 2)*/
1313  {
1314  std::memset(buffer.data() + ghost_targets_data[i][1],
1315  0.0,
1316  (ghost_targets_data[i][2]) * sizeof(Number));
1317  }
1318  }
1319 
1320  const int ierr =
1321  MPI_Waitall(requests.size(), requests.data(), MPI_STATUSES_IGNORE);
1322  AssertThrowMPI(ierr);
1323 #endif
1324  }
1325 
1326 
1327 
1328  unsigned int
1330  {
1331  return n_local_elements;
1332  }
1333 
1334 
1335 
1336  unsigned int
1338  {
1339  return n_ghost_elements;
1340  }
1341 
1342 
1343 
1344  unsigned int
1346  {
1347  if (import_targets_data.size() == 0)
1348  return 0;
1349  return import_targets_data.back()[1] + import_targets_data.back()[2];
1350  }
1351 
1352 
1353 
1354  unsigned int
1356  {
1357  return sm_import_ranks.size() + sm_ghost_ranks.size(); // TODO
1358  }
1359 
1360 
1361 
1363  Full::size() const
1364  {
1365  return n_global_elements;
1366  }
1367 
1368 
1369 
1370  const MPI_Comm &
1372  {
1373  return this->comm_sm;
1374  }
1375 
1376 
1377 
1378  void
1380  {
1381  reset_ghost_values_impl(ghost_array);
1382  }
1383 
1384 
1385 
1386  void
1387  Full::reset_ghost_values(const ArrayView<float> &ghost_array) const
1388  {
1389  reset_ghost_values_impl(ghost_array);
1390  }
1391 
1392 
1393 
1394  template <typename Number>
1395  void
1397  {
1398  // reset ghost values coming from shared-memory neighbors
1399  // TODO: only needed if values are buffered
1400  for (const auto &i : sm_export_data_this.second)
1401  std::memset(ghost_array.data() + (i.first - n_local_elements),
1402  0,
1403  sizeof(Number) * i.second);
1404 
1405  // reset ghost values coming from remote neighbors
1406  for (const auto &i : ghost_indices_subset_data.second)
1407  std::memset(ghost_array.data() + i.first,
1408  0,
1409  sizeof(Number) * i.second);
1410  }
1411 
1412 
1413 
1414  } // namespace VectorDataExchange
1415  } // namespace MatrixFreeFunctions
1416 } // namespace internal
1417 
1418 
value_type * data() const noexcept
Definition: array_view.h:551
std::size_t size() const
Definition: array_view.h:574
void export_to_ghosted_array_finish_impl(const ArrayView< const Number > &locally_owned_array, const std::vector< ArrayView< const Number >> &shared_arrays, const ArrayView< Number > &ghost_array, std::vector< MPI_Request > &requests) const
void export_to_ghosted_array_start_impl(const unsigned int communication_channel, const ArrayView< const Number > &locally_owned_array, const std::vector< ArrayView< const Number >> &shared_arrays, const ArrayView< Number > &ghost_array, const ArrayView< Number > &temporary_storage, std::vector< MPI_Request > &requests) const
void import_from_ghosted_array_start(const VectorOperation::values vector_operation, const unsigned int communication_channel, const ArrayView< const double > &locally_owned_array, const std::vector< ArrayView< const double >> &shared_arrays, const ArrayView< double > &ghost_array, const ArrayView< double > &temporary_storage, std::vector< MPI_Request > &requests) const override
void reset_ghost_values(const ArrayView< double > &ghost_array) const override
std::vector< std::array< unsigned int, 3 > > ghost_targets_data
std::pair< std::vector< unsigned int >, std::vector< std::pair< unsigned int, unsigned int > > > sm_export_data_this
std::pair< std::vector< unsigned int >, std::vector< std::pair< unsigned int, unsigned int > > > sm_export_data
std::vector< std::array< unsigned int, 3 > > import_targets_data
std::pair< std::vector< unsigned int >, std::vector< std::pair< unsigned int, unsigned int > > > ghost_indices_subset_data
Full(const std::shared_ptr< const Utilities::MPI::Partitioner > &partitioner, const MPI_Comm &communicator_sm)
void import_from_ghosted_array_finish_impl(const VectorOperation::values vector_operation, const ArrayView< Number > &locally_owned_storage, const std::vector< ArrayView< const Number >> &shared_arrays, const ArrayView< Number > &ghost_array, const ArrayView< const Number > &temporary_storage, std::vector< MPI_Request > &requests) const
void import_from_ghosted_array_finish(const VectorOperation::values vector_operation, const ArrayView< double > &locally_owned_storage, const std::vector< ArrayView< const double >> &shared_arrays, const ArrayView< double > &ghost_array, const ArrayView< const double > &temporary_storage, std::vector< MPI_Request > &requests) const override
std::pair< std::vector< unsigned int >, std::vector< std::pair< unsigned int, unsigned int > > > sm_import_data
void export_to_ghosted_array_start(const unsigned int communication_channel, const ArrayView< const double > &locally_owned_array, const std::vector< ArrayView< const double >> &shared_arrays, const ArrayView< double > &ghost_array, const ArrayView< double > &temporary_storage, std::vector< MPI_Request > &requests) const override
void reset_ghost_values_impl(const ArrayView< Number > &ghost_array) const
std::pair< std::vector< unsigned int >, std::vector< std::pair< unsigned int, unsigned int > > > sm_import_data_this
void import_from_ghosted_array_start_impl(const VectorOperation::values vector_operation, const unsigned int communication_channel, const ArrayView< const Number > &locally_owned_array, const std::vector< ArrayView< const Number >> &shared_arrays, const ArrayView< Number > &ghost_array, const ArrayView< Number > &temporary_storage, std::vector< MPI_Request > &requests) const
void export_to_ghosted_array_finish(const ArrayView< const double > &locally_owned_array, const std::vector< ArrayView< const double >> &shared_arrays, const ArrayView< double > &ghost_array, std::vector< MPI_Request > &requests) const override
virtual types::global_dof_index size() const override
std::pair< std::vector< unsigned int >, std::vector< std::pair< unsigned int, unsigned int > > > import_indices_data
const std::shared_ptr< const Utilities::MPI::Partitioner > partitioner
PartitionerWrapper(const std::shared_ptr< const Utilities::MPI::Partitioner > &partitioner)
void export_to_ghosted_array_start(const unsigned int communication_channel, const ArrayView< const double > &locally_owned_array, const std::vector< ArrayView< const double >> &shared_arrays, const ArrayView< double > &ghost_array, const ArrayView< double > &temporary_storage, std::vector< MPI_Request > &requests) const override
void import_from_ghosted_array_finish(const VectorOperation::values vector_operation, const ArrayView< double > &locally_owned_storage, const std::vector< ArrayView< const double >> &shared_arrays, const ArrayView< double > &ghost_array, const ArrayView< const double > &temporary_storage, std::vector< MPI_Request > &requests) const override
void reset_ghost_values_impl(const ArrayView< Number > &ghost_array) const
void reset_ghost_values(const ArrayView< double > &ghost_array) const override
void import_from_ghosted_array_start(const VectorOperation::values vector_operation, const unsigned int communication_channel, const ArrayView< const double > &locally_owned_array, const std::vector< ArrayView< const double >> &shared_arrays, const ArrayView< double > &ghost_array, const ArrayView< double > &temporary_storage, std::vector< MPI_Request > &requests) const override
void export_to_ghosted_array_finish(const ArrayView< const double > &locally_owned_array, const std::vector< ArrayView< const double >> &shared_arrays, const ArrayView< double > &ghost_array, std::vector< MPI_Request > &requests) const override
#define DEAL_II_NAMESPACE_OPEN
Definition: config.h:396
#define DEAL_II_RESTRICT
Definition: config.h:98
#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 AssertThrowMPI(error_code)
Definition: exceptions.h:1746
#define AssertIndexRange(index, range)
Definition: exceptions.h:1690
std::vector< value_type > split(const typename ::Triangulation< dim, spacedim >::cell_iterator &parent, const value_type parent_value)
Tensor< 2, dim, Number > l(const Tensor< 2, dim, Number > &F, const Tensor< 2, dim, Number > &dF_dt)
TrilinosWrappers::types::int_type n_global_elements(const Epetra_BlockMap &map)
bool job_supports_mpi()
Definition: mpi.cc:1097
const std::vector< unsigned int > mpi_processes_within_communicator(const MPI_Comm &comm_large, const MPI_Comm &comm_small)
Definition: mpi.cc:140
std::pair< std::vector< unsigned int >, std::vector< std::pair< unsigned int, unsigned int > > > compress_to_contiguous_ranges(const std::vector< unsigned int > &sm_export_ptr, const std::vector< unsigned int > &sm_export_indices)
unsigned int global_dof_index
Definition: types.h:76