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