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\}}\)
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
35namespace 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
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,
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,
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,
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,
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 =
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 =
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 {
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 {
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 {
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 {
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() +
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,
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,
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],
923 Utilities::MPI::internal::mpi_type_id(data_this.data()),
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 -
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 {
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
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 {
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
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> {
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
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
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_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(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
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
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_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_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
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
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
Full(const std::shared_ptr< const Utilities::MPI::Partitioner > &partitioner, const MPI_Comm &communicator_sm)
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
std::pair< std::vector< unsigned int >, std::vector< std::pair< unsigned int, unsigned int > > > sm_import_data
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 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
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
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
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 reset_ghost_values_impl(const ArrayView< Number > &ghost_array) 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
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
#define DEAL_II_NAMESPACE_OPEN
Definition: config.h:402
#define DEAL_II_RESTRICT
Definition: config.h:101
#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 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)
*braid_SplitCommworld & comm