Tpetra parallel linear algebra Version of the Day
Tpetra_Distributor.hpp
1// @HEADER
2// ***********************************************************************
3//
4// Tpetra: Templated Linear Algebra Services Package
5// Copyright (2008) Sandia Corporation
6//
7// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
8// the U.S. Government retains certain rights in this software.
9//
10// Redistribution and use in source and binary forms, with or without
11// modification, are permitted provided that the following conditions are
12// met:
13//
14// 1. Redistributions of source code must retain the above copyright
15// notice, this list of conditions and the following disclaimer.
16//
17// 2. Redistributions in binary form must reproduce the above copyright
18// notice, this list of conditions and the following disclaimer in the
19// documentation and/or other materials provided with the distribution.
20//
21// 3. Neither the name of the Corporation nor the names of the
22// contributors may be used to endorse or promote products derived from
23// this software without specific prior written permission.
24//
25// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
26// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
29// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
30// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
31// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
32// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
33// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
34// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
35// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36//
37// ************************************************************************
38// @HEADER
39
40#ifndef TPETRA_DISTRIBUTOR_HPP
41#define TPETRA_DISTRIBUTOR_HPP
42
43#include "Tpetra_Details_DistributorActor.hpp"
44#include "Tpetra_Details_DistributorPlan.hpp"
45
46#include "Tpetra_Util.hpp"
47#include "Teuchos_as.hpp"
48#include "Teuchos_Describable.hpp"
49#include "Teuchos_ParameterListAcceptorDefaultBase.hpp"
50#include "Teuchos_VerboseObject.hpp"
52
53#include "KokkosCompat_View.hpp"
54#include "Kokkos_Core.hpp"
55#include "Kokkos_TeuchosCommAdapters.hpp"
56#include <memory>
57#include <sstream>
58#include <type_traits>
59
60namespace Tpetra {
61
68 Teuchos::Array<std::string> distributorSendTypes ();
69
138 public Teuchos::Describable,
139 public Teuchos::ParameterListAcceptorDefaultBase {
140 public:
142
143
152 explicit Distributor (const Teuchos::RCP<const Teuchos::Comm<int> >& comm);
153
165 Distributor (const Teuchos::RCP<const Teuchos::Comm<int> >& comm,
166 const Teuchos::RCP<Teuchos::FancyOStream>& out);
167
181 Distributor (const Teuchos::RCP<const Teuchos::Comm<int> >& comm,
182 const Teuchos::RCP<Teuchos::ParameterList>& plist);
183
200 Distributor (const Teuchos::RCP<const Teuchos::Comm<int> >& comm,
201 const Teuchos::RCP<Teuchos::FancyOStream>& out,
202 const Teuchos::RCP<Teuchos::ParameterList>& plist);
203
205 Distributor (const Distributor& distributor);
206
211 virtual ~Distributor () = default;
212
218 void swap (Distributor& rhs);
219
221
223
228 void setParameterList (const Teuchos::RCP<Teuchos::ParameterList>& plist);
229
234 Teuchos::RCP<const Teuchos::ParameterList> getValidParameters () const;
235
237
239
259 size_t createFromSends (const Teuchos::ArrayView<const int>& exportProcIDs);
260
294 template <class Ordinal>
295 void
296 createFromRecvs (const Teuchos::ArrayView<const Ordinal>& remoteIDs,
297 const Teuchos::ArrayView<const int>& remoteProcIDs,
298 Teuchos::Array<Ordinal>& exportIDs,
299 Teuchos::Array<int>& exportProcIDs);
300
308 void
309 createFromSendsAndRecvs (const Teuchos::ArrayView<const int>& exportProcIDs,
310 const Teuchos::ArrayView<const int>& remoteProcIDs);
311
313
315
319 size_t getNumReceives() const;
320
324 size_t getNumSends() const;
325
327 bool hasSelfMessage() const;
328
330 size_t getMaxSendLength() const;
331
333 size_t getTotalReceiveLength() const;
334
339 Teuchos::ArrayView<const int> getProcsFrom() const;
340
345 Teuchos::ArrayView<const int> getProcsTo() const;
346
354 Teuchos::ArrayView<const size_t> getLengthsFrom() const;
355
363 Teuchos::ArrayView<const size_t> getLengthsTo() const;
364
370 return plan_.howInitialized();
371 }
372
374
376
387 Teuchos::RCP<Distributor> getReverse(bool create=true) const;
388
390
392
413 template <class Packet>
414 void
415 doPostsAndWaits (const Teuchos::ArrayView<const Packet> &exports,
416 size_t numPackets,
417 const Teuchos::ArrayView<Packet> &imports);
418
440 template <class Packet>
441 void
442 doPostsAndWaits (const Teuchos::ArrayView<const Packet> &exports,
443 const Teuchos::ArrayView<const size_t>& numExportPacketsPerLID,
444 const Teuchos::ArrayView<Packet> &imports,
445 const Teuchos::ArrayView<const size_t>& numImportPacketsPerLID);
446
471 template <class Packet>
472 void
473 doPosts (const Teuchos::ArrayRCP<const Packet> &exports,
474 size_t numPackets,
475 const Teuchos::ArrayRCP<Packet> &imports);
476
495 template <class Packet>
496 void
497 doPosts (const Teuchos::ArrayRCP<const Packet> &exports,
498 const Teuchos::ArrayView<const size_t>& numExportPacketsPerLID,
499 const Teuchos::ArrayRCP<Packet> &imports,
500 const Teuchos::ArrayView<const size_t>& numImportPacketsPerLID);
501
508 void doWaits ();
509
514 template <class Packet>
515 void
516 doReversePostsAndWaits (const Teuchos::ArrayView<const Packet> &exports,
517 size_t numPackets,
518 const Teuchos::ArrayView<Packet> &imports);
519
524 template <class Packet>
525 void
526 doReversePostsAndWaits (const Teuchos::ArrayView<const Packet> &exports,
527 const Teuchos::ArrayView<const size_t>& numExportPacketsPerLID,
528 const Teuchos::ArrayView<Packet> &imports,
529 const Teuchos::ArrayView<const size_t>& numImportPacketsPerLID);
530
535 template <class Packet>
536 void
537 doReversePosts (const Teuchos::ArrayRCP<const Packet> &exports,
538 size_t numPackets,
539 const Teuchos::ArrayRCP<Packet> &imports);
540
545 template <class Packet>
546 void
547 doReversePosts (const Teuchos::ArrayRCP<const Packet> &exports,
548 const Teuchos::ArrayView<const size_t>& numExportPacketsPerLID,
549 const Teuchos::ArrayRCP<Packet> &imports,
550 const Teuchos::ArrayView<const size_t>& numImportPacketsPerLID);
551
558 void doReverseWaits ();
559
580 template <class ExpView, class ImpView>
581 typename std::enable_if<(Kokkos::Impl::is_view<ExpView>::value && Kokkos::Impl::is_view<ImpView>::value)>::type
583 const ExpView &exports,
584 size_t numPackets,
585 const ImpView &imports);
586
608 template <class ExpView, class ImpView>
609 typename std::enable_if<(Kokkos::Impl::is_view<ExpView>::value && Kokkos::Impl::is_view<ImpView>::value)>::type
610 doPostsAndWaits (const ExpView &exports,
611 const Teuchos::ArrayView<const size_t>& numExportPacketsPerLID,
612 const ImpView &imports,
613 const Teuchos::ArrayView<const size_t>& numImportPacketsPerLID);
614
639 template <class ExpView, class ImpView>
640 typename std::enable_if<(Kokkos::Impl::is_view<ExpView>::value && Kokkos::Impl::is_view<ImpView>::value)>::type
641 doPosts (const ExpView &exports,
642 size_t numPackets,
643 const ImpView &imports);
644
663 template <class ExpView, class ImpView>
664 typename std::enable_if<(Kokkos::Impl::is_view<ExpView>::value && Kokkos::Impl::is_view<ImpView>::value)>::type
665 doPosts (const ExpView &exports,
666 const Teuchos::ArrayView<const size_t>& numExportPacketsPerLID,
667 const ImpView &imports,
668 const Teuchos::ArrayView<const size_t>& numImportPacketsPerLID);
669
674 template <class ExpView, class ImpView>
675 typename std::enable_if<(Kokkos::Impl::is_view<ExpView>::value && Kokkos::Impl::is_view<ImpView>::value)>::type
676 doReversePostsAndWaits (const ExpView &exports,
677 size_t numPackets,
678 const ImpView &imports);
679
684 template <class ExpView, class ImpView>
685 typename std::enable_if<(Kokkos::Impl::is_view<ExpView>::value && Kokkos::Impl::is_view<ImpView>::value)>::type
686 doReversePostsAndWaits (const ExpView &exports,
687 const Teuchos::ArrayView<const size_t>& numExportPacketsPerLID,
688 const ImpView &imports,
689 const Teuchos::ArrayView<const size_t>& numImportPacketsPerLID);
690
695 template <class ExpView, class ImpView>
696 typename std::enable_if<(Kokkos::Impl::is_view<ExpView>::value && Kokkos::Impl::is_view<ImpView>::value)>::type
697 doReversePosts (const ExpView &exports,
698 size_t numPackets,
699 const ImpView &imports);
700
705 template <class ExpView, class ImpView>
706 typename std::enable_if<(Kokkos::Impl::is_view<ExpView>::value && Kokkos::Impl::is_view<ImpView>::value)>::type
707 doReversePosts (const ExpView &exports,
708 const Teuchos::ArrayView<const size_t>& numExportPacketsPerLID,
709 const ImpView &imports,
710 const Teuchos::ArrayView<const size_t>& numImportPacketsPerLID);
711
715 void getLastDoStatistics(size_t & bytes_sent, size_t & bytes_recvd) const{
716 bytes_sent = lastRoundBytesSend_;
717 bytes_recvd = lastRoundBytesRecv_;
718 }
719
721
723
725 std::string description() const;
726
748 void
749 describe (Teuchos::FancyOStream& out,
750 const Teuchos::EVerbosityLevel verbLevel =
751 Teuchos::Describable::verbLevel_default) const;
753
758 const Details::DistributorPlan& getPlan() const { return plan_; }
759 private:
761 Details::DistributorActor actor_;
762
764
765
767 static bool getVerbose();
768
773 std::unique_ptr<std::string>
774 createPrefix(const char methodName[]) const;
775
777 bool verbose_ = getVerbose();
779
784 mutable Teuchos::RCP<Distributor> reverseDistributor_;
785
787 size_t lastRoundBytesSend_;
788
790 size_t lastRoundBytesRecv_;
791
804 template <class Ordinal>
805 void computeSends (const Teuchos::ArrayView<const Ordinal> &remoteGIDs,
806 const Teuchos::ArrayView<const int> &remoteProcIDs,
807 Teuchos::Array<Ordinal> &exportGIDs,
808 Teuchos::Array<int> &exportProcIDs);
809
811 void createReverseDistributor() const;
812
813
818 std::string
819 localDescribeToString (const Teuchos::EVerbosityLevel vl) const;
820 }; // class Distributor
821
822
823 template <class Packet>
825 doPostsAndWaits (const Teuchos::ArrayView<const Packet>& exports,
826 size_t numPackets,
827 const Teuchos::ArrayView<Packet>& imports)
828 {
829 using Teuchos::arcp;
830 using Teuchos::ArrayRCP;
831 typedef typename ArrayRCP<const Packet>::size_type size_type;
832
833 // doPosts() accepts the exports and imports arrays as ArrayRCPs,
834 // requiring that the memory location is persisting (as is
835 // necessary for nonblocking receives). However, it need only
836 // persist until doWaits() completes, so it is safe for us to use
837 // a nonpersisting reference in this case. The use of a
838 // nonpersisting reference is purely a performance optimization.
839
840 //const Packet* exportsPtr = exports.getRawPtr();
841 //ArrayRCP<const Packet> exportsArcp (exportsPtr, static_cast<size_type> (0),
842 // exports.size(), false);
843 ArrayRCP<const Packet> exportsArcp (exports.getRawPtr (),
844 static_cast<size_type> (0),
845 exports.size(), false);
846
847 // For some reason, neither of the options below (that use arcp)
848 // compile for Packet=std::complex<double> with GCC 4.5.1. The
849 // issue only arises with the exports array. This is why we
850 // construct a separate nonowning ArrayRCP.
851
852 // doPosts (arcp<const Packet> (exports.getRawPtr(), 0, exports.size(), false),
853 // numPackets,
854 // arcp<Packet> (imports.getRawPtr(), 0, imports.size(), false));
855 // doPosts (arcp<const Packet> (exportsPtr, 0, exports.size(), false),
856 // numPackets,
857 // arcp<Packet> (imports.getRawPtr(), 0, imports.size(), false));
858 doPosts (exportsArcp,
859 numPackets,
860 arcp<Packet> (imports.getRawPtr (), 0, imports.size (), false));
861 doWaits ();
862
863 lastRoundBytesSend_ = exports.size () * sizeof (Packet);
864 lastRoundBytesRecv_ = imports.size () * sizeof (Packet);
865 }
866
867 template <class Packet>
869 doPostsAndWaits (const Teuchos::ArrayView<const Packet>& exports,
870 const Teuchos::ArrayView<const size_t>& numExportPacketsPerLID,
871 const Teuchos::ArrayView<Packet> &imports,
872 const Teuchos::ArrayView<const size_t>& numImportPacketsPerLID)
873 {
874 using Teuchos::arcp;
875 using Teuchos::ArrayRCP;
876
877 // doPosts() accepts the exports and imports arrays as ArrayRCPs,
878 // requiring that the memory location is persisting (as is
879 // necessary for nonblocking receives). However, it need only
880 // persist until doWaits() completes, so it is safe for us to use
881 // a nonpersisting reference in this case.
882
883 // mfh 04 Apr 2012: For some reason, calling arcp<const Packet>
884 // for Packet=std::complex<T> (e.g., T=float) fails to compile
885 // with some versions of GCC. The issue only arises with the
886 // exports array. This is why we construct a separate nonowning
887 // ArrayRCP.
888 typedef typename ArrayRCP<const Packet>::size_type size_type;
889 ArrayRCP<const Packet> exportsArcp (exports.getRawPtr (),
890 static_cast<size_type> (0),
891 exports.size (), false);
892 // mfh 04 Apr 2012: This is the offending code. This statement
893 // would normally be in place of "exportsArcp" in the
894 // doPosts() call below.
895 //arcp<const Packet> (exports.getRawPtr(), 0, exports.size(), false),
896 doPosts (exportsArcp,
897 numExportPacketsPerLID,
898 arcp<Packet> (imports.getRawPtr (), 0, imports.size (), false),
899 numImportPacketsPerLID);
900 doWaits ();
901
902 lastRoundBytesSend_ = exports.size () * sizeof (Packet);
903 lastRoundBytesRecv_ = imports.size () * sizeof (Packet);
904 }
905
906
907 template <class Packet>
909 doPosts (const Teuchos::ArrayRCP<const Packet>& exports,
910 size_t numPackets,
911 const Teuchos::ArrayRCP<Packet>& imports)
912 {
913 Kokkos::View<const Packet*, Kokkos::HostSpace> exportsView(exports.get(), exports.size());
914 Kokkos::View<Packet*, Kokkos::HostSpace> importsView(imports.get(), imports.size());
915 doPosts(exportsView, numPackets, importsView);
916 }
917
918 template <class Packet>
920 doPosts (const Teuchos::ArrayRCP<const Packet>& exports,
921 const Teuchos::ArrayView<const size_t>& numExportPacketsPerLID,
922 const Teuchos::ArrayRCP<Packet>& imports,
923 const Teuchos::ArrayView<const size_t>& numImportPacketsPerLID)
924 {
925 Kokkos::View<const Packet*, Kokkos::HostSpace> exportsView(exports.get(), exports.size());
926 Kokkos::View<Packet*, Kokkos::HostSpace> importsView(imports.get(), imports.size());
927 doPosts(exportsView, numExportPacketsPerLID, importsView, numImportPacketsPerLID);
928 }
929
930 template <class Packet>
932 doReversePostsAndWaits (const Teuchos::ArrayView<const Packet>& exports,
933 size_t numPackets,
934 const Teuchos::ArrayView<Packet>& imports)
935 {
936 using Teuchos::arcp;
937 using Teuchos::ArrayRCP;
938 using Teuchos::as;
939
940 // doReversePosts() takes exports and imports as ArrayRCPs,
941 // requiring that the memory locations are persisting. However,
942 // they need only persist within the scope of that routine, so it
943 // is safe for us to use nonpersisting references in this case.
944
945 // mfh 04 Apr 2012: For some reason, calling arcp<const Packet>
946 // for Packet=std::complex<T> (e.g., T=float) fails to compile
947 // with some versions of GCC. The issue only arises with the
948 // exports array. This is why we construct a separate nonowning
949 // ArrayRCP.
950 typedef typename ArrayRCP<const Packet>::size_type size_type;
951 ArrayRCP<const Packet> exportsArcp (exports.getRawPtr(), as<size_type> (0),
952 exports.size(), false);
953 // mfh 04 Apr 2012: This is the offending code. This statement
954 // would normally be in place of "exportsArcp" in the
955 // doReversePosts() call below.
956 //arcp<const Packet> (exports.getRawPtr(), 0, exports.size(), false)
957 doReversePosts (exportsArcp,
958 numPackets,
959 arcp<Packet> (imports.getRawPtr (), 0, imports.size (), false));
961
962 lastRoundBytesSend_ = exports.size() * sizeof(Packet);
963 lastRoundBytesRecv_ = imports.size() * sizeof(Packet);
964 }
965
966 template <class Packet>
968 doReversePostsAndWaits (const Teuchos::ArrayView<const Packet>& exports,
969 const Teuchos::ArrayView<const size_t>& numExportPacketsPerLID,
970 const Teuchos::ArrayView<Packet> &imports,
971 const Teuchos::ArrayView<const size_t>& numImportPacketsPerLID)
972 {
973 using Teuchos::as;
974 using Teuchos::arcp;
975 using Teuchos::ArrayRCP;
976
977 // doReversePosts() accepts the exports and imports arrays as
978 // ArrayRCPs, requiring that the memory location is persisting (as
979 // is necessary for nonblocking receives). However, it need only
980 // persist until doReverseWaits() completes, so it is safe for us
981 // to use a nonpersisting reference in this case. The use of a
982 // nonpersisting reference is purely a performance optimization.
983
984 // mfh 02 Apr 2012: For some reason, calling arcp<const Packet>
985 // for Packet=std::complex<double> fails to compile with some
986 // versions of GCC. The issue only arises with the exports array.
987 // This is why we construct a separate nonowning ArrayRCP.
988 typedef typename ArrayRCP<const Packet>::size_type size_type;
989 ArrayRCP<const Packet> exportsArcp (exports.getRawPtr (), as<size_type> (0),
990 exports.size (), false);
991 doReversePosts (exportsArcp,
992 numExportPacketsPerLID,
993 arcp<Packet> (imports.getRawPtr (), 0, imports.size (), false),
994 numImportPacketsPerLID);
996
997 lastRoundBytesSend_ = exports.size() * sizeof(Packet);
998 lastRoundBytesRecv_ = imports.size() * sizeof(Packet);
999 }
1000
1001 template <class Packet>
1003 doReversePosts (const Teuchos::ArrayRCP<const Packet>& exports,
1004 size_t numPackets,
1005 const Teuchos::ArrayRCP<Packet>& imports)
1006 {
1007 // FIXME (mfh 29 Mar 2012) WHY?
1008 TEUCHOS_TEST_FOR_EXCEPTION(
1009 ! plan_.getIndicesTo().is_null(), std::runtime_error,
1010 "Tpetra::Distributor::doReversePosts(3 args): Can only do reverse "
1011 "communication when original data are blocked by process.");
1012 if (reverseDistributor_.is_null ()) {
1013 createReverseDistributor ();
1014 }
1015 reverseDistributor_->doPosts (exports, numPackets, imports);
1016 }
1017
1018 template <class Packet>
1020 doReversePosts (const Teuchos::ArrayRCP<const Packet>& exports,
1021 const Teuchos::ArrayView<const size_t>& numExportPacketsPerLID,
1022 const Teuchos::ArrayRCP<Packet>& imports,
1023 const Teuchos::ArrayView<const size_t>& numImportPacketsPerLID)
1024 {
1025 // FIXME (mfh 29 Mar 2012) WHY?
1026 TEUCHOS_TEST_FOR_EXCEPTION(
1027 ! plan_.getIndicesTo().is_null(), std::runtime_error,
1028 "Tpetra::Distributor::doReversePosts(3 args): Can only do reverse "
1029 "communication when original data are blocked by process.");
1030 if (reverseDistributor_.is_null ()) {
1031 createReverseDistributor ();
1032 }
1033 reverseDistributor_->doPosts (exports, numExportPacketsPerLID,
1034 imports, numImportPacketsPerLID);
1035 }
1036
1037 template <class ExpView, class ImpView>
1038 typename std::enable_if<(Kokkos::Impl::is_view<ExpView>::value && Kokkos::Impl::is_view<ImpView>::value)>::type
1040 doPostsAndWaits (const ExpView& exports,
1041 size_t numPackets,
1042 const ImpView& imports)
1043 {
1044 actor_.doPostsAndWaits(plan_, exports, numPackets, imports);
1045 }
1046
1047 template <class ExpView, class ImpView>
1048 typename std::enable_if<(Kokkos::Impl::is_view<ExpView>::value && Kokkos::Impl::is_view<ImpView>::value)>::type
1050 doPostsAndWaits(const ExpView& exports,
1051 const Teuchos::ArrayView<const size_t>& numExportPacketsPerLID,
1052 const ImpView& imports,
1053 const Teuchos::ArrayView<const size_t>& numImportPacketsPerLID)
1054 {
1055 actor_.doPostsAndWaits(plan_, exports, numExportPacketsPerLID, imports, numImportPacketsPerLID);
1056 }
1057
1058
1059 template <class ExpView, class ImpView>
1060 typename std::enable_if<(Kokkos::Impl::is_view<ExpView>::value && Kokkos::Impl::is_view<ImpView>::value)>::type
1062 doPosts (const ExpView &exports,
1063 size_t numPackets,
1064 const ImpView &imports)
1065 {
1066 actor_.doPosts(plan_, exports, numPackets, imports);
1067 }
1068
1069 template <class ExpView, class ImpView>
1070 typename std::enable_if<(Kokkos::Impl::is_view<ExpView>::value && Kokkos::Impl::is_view<ImpView>::value)>::type
1072 doPosts (const ExpView &exports,
1073 const Teuchos::ArrayView<const size_t>& numExportPacketsPerLID,
1074 const ImpView &imports,
1075 const Teuchos::ArrayView<const size_t>& numImportPacketsPerLID)
1076 {
1077 actor_.doPosts(plan_, exports, numExportPacketsPerLID, imports, numImportPacketsPerLID);
1078 }
1079
1080 template <class ExpView, class ImpView>
1081 typename std::enable_if<(Kokkos::Impl::is_view<ExpView>::value && Kokkos::Impl::is_view<ImpView>::value)>::type
1083 doReversePostsAndWaits (const ExpView& exports,
1084 size_t numPackets,
1085 const ImpView& imports)
1086 {
1087 doReversePosts (exports, numPackets, imports);
1088 doReverseWaits ();
1089 }
1090
1091 template <class ExpView, class ImpView>
1092 typename std::enable_if<(Kokkos::Impl::is_view<ExpView>::value && Kokkos::Impl::is_view<ImpView>::value)>::type
1094 doReversePostsAndWaits (const ExpView& exports,
1095 const Teuchos::ArrayView<const size_t>& numExportPacketsPerLID,
1096 const ImpView& imports,
1097 const Teuchos::ArrayView<const size_t>& numImportPacketsPerLID)
1098 {
1099 doReversePosts (exports, numExportPacketsPerLID, imports,
1100 numImportPacketsPerLID);
1101 doReverseWaits ();
1102 }
1103
1104 template <class ExpView, class ImpView>
1105 typename std::enable_if<(Kokkos::Impl::is_view<ExpView>::value && Kokkos::Impl::is_view<ImpView>::value)>::type
1107 doReversePosts (const ExpView &exports,
1108 size_t numPackets,
1109 const ImpView &imports)
1110 {
1111 // FIXME (mfh 29 Mar 2012) WHY?
1112 TEUCHOS_TEST_FOR_EXCEPTION(
1113 ! plan_.getIndicesTo().is_null(), std::runtime_error,
1114 "Tpetra::Distributor::doReversePosts(3 args): Can only do "
1115 "reverse communication when original data are blocked by process.");
1116 if (reverseDistributor_.is_null ()) {
1117 createReverseDistributor ();
1118 }
1119 reverseDistributor_->doPosts (exports, numPackets, imports);
1120 }
1121
1122 template <class ExpView, class ImpView>
1123 typename std::enable_if<(Kokkos::Impl::is_view<ExpView>::value && Kokkos::Impl::is_view<ImpView>::value)>::type
1125 doReversePosts (const ExpView &exports,
1126 const Teuchos::ArrayView<const size_t>& numExportPacketsPerLID,
1127 const ImpView &imports,
1128 const Teuchos::ArrayView<const size_t>& numImportPacketsPerLID)
1129 {
1130 // FIXME (mfh 29 Mar 2012) WHY?
1131 TEUCHOS_TEST_FOR_EXCEPTION(
1132 ! plan_.getIndicesTo().is_null(), std::runtime_error,
1133 "Tpetra::Distributor::doReversePosts(3 args): Can only do "
1134 "reverse communication when original data are blocked by process.");
1135 if (reverseDistributor_.is_null ()) {
1136 createReverseDistributor ();
1137 }
1138 reverseDistributor_->doPosts (exports, numExportPacketsPerLID,
1139 imports, numImportPacketsPerLID);
1140 }
1141
1142 template <class OrdinalType>
1143 void Distributor::
1144 computeSends(const Teuchos::ArrayView<const OrdinalType>& importGIDs,
1145 const Teuchos::ArrayView<const int>& importProcIDs,
1146 Teuchos::Array<OrdinalType>& exportGIDs,
1147 Teuchos::Array<int>& exportProcIDs)
1148 {
1149 // NOTE (mfh 19 Apr 2012): There was a note on this code saying:
1150 // "assumes that size_t >= Ordinal". The code certainly does
1151 // assume that sizeof(size_t) >= sizeof(OrdinalType) as well as
1152 // sizeof(size_t) >= sizeof(int). This is because it casts the
1153 // OrdinalType elements of importGIDs (along with their
1154 // corresponding process IDs, as int) to size_t, and does a
1155 // doPostsAndWaits<size_t>() to send the packed data.
1156 using Teuchos::Array;
1157 using Teuchos::ArrayView;
1158 using std::endl;
1159 using size_type = typename ArrayView<const OrdinalType>::size_type;
1160 const char errPrefix[] = "Tpetra::Distributor::computeSends: ";
1161 const char suffix[] =
1162 " Please report this bug to the Tpetra developers.";
1163
1164 const int myRank = plan_.getComm()->getRank ();
1165
1166 TEUCHOS_TEST_FOR_EXCEPTION
1167 (importGIDs.size () != importProcIDs.size (),
1168 std::invalid_argument, errPrefix << "On Process " << myRank
1169 << ": importProcIDs.size()=" << importProcIDs.size()
1170 << " != importGIDs.size()=" << importGIDs.size() << ".");
1171
1172 const size_type numImports = importProcIDs.size();
1173 Array<size_t> importObjs(2*numImports);
1174 // Pack pairs (importGIDs[i], my process ID) to send into importObjs.
1175 for (size_type i = 0; i < numImports; ++i) {
1176 importObjs[2*i] = static_cast<size_t>(importGIDs[i]);
1177 importObjs[2*i+1] = static_cast<size_t>(myRank);
1178 }
1179 //
1180 // Use a temporary Distributor to send the (importGIDs[i], myRank)
1181 // pairs to importProcIDs[i].
1182 //
1183 Distributor tempPlan(plan_.getComm());
1184 // mfh 20 Mar 2014: An extra-cautious cast from unsigned to
1185 // signed, in order to forestall any possible causes for Bug 6069.
1186 const size_t numExportsAsSizeT =
1187 tempPlan.createFromSends(importProcIDs);
1188 const size_type numExports =
1189 static_cast<size_type>(numExportsAsSizeT);
1190 TEUCHOS_TEST_FOR_EXCEPTION
1191 (numExports < 0, std::logic_error, errPrefix <<
1192 "tempPlan.createFromSends() returned numExports="
1193 << numExportsAsSizeT << " as a size_t, which overflows to "
1194 << numExports << " when cast to " <<
1195 Teuchos::TypeNameTraits<size_type>::name () << "." << suffix);
1196 TEUCHOS_TEST_FOR_EXCEPTION
1197 (size_type(tempPlan.getTotalReceiveLength()) != numExports,
1198 std::logic_error, errPrefix << "tempPlan.getTotalReceiveLength()="
1199 << tempPlan.getTotalReceiveLength () << " != numExports="
1200 << numExports << "." << suffix);
1201
1202 if (numExports > 0) {
1203 exportGIDs.resize(numExports);
1204 exportProcIDs.resize(numExports);
1205 }
1206
1207 // exportObjs: Packed receive buffer. (exportObjs[2*i],
1208 // exportObjs[2*i+1]) will give the (GID, PID) pair for export i,
1209 // after tempPlan.doPostsAndWaits(...) finishes below.
1210 //
1211 // FIXME (mfh 19 Mar 2014) This only works if OrdinalType fits in
1212 // size_t. This issue might come up, for example, on a 32-bit
1213 // machine using 64-bit global indices. I will add a check here
1214 // for that case.
1215 static_assert(sizeof(size_t) >= sizeof(OrdinalType),
1216 "Tpetra::Distributor::computeSends: "
1217 "sizeof(size_t) < sizeof(OrdinalType).");
1218
1219 TEUCHOS_TEST_FOR_EXCEPTION
1220 (tempPlan.getTotalReceiveLength () < size_t(numExports),
1221 std::logic_error,
1222 errPrefix << "tempPlan.getTotalReceiveLength()="
1223 << tempPlan.getTotalReceiveLength() << " < numExports="
1224 << numExports << "." << suffix);
1225
1226 Array<size_t> exportObjs (tempPlan.getTotalReceiveLength () * 2);
1227 tempPlan.doPostsAndWaits<size_t> (importObjs (), 2, exportObjs ());
1228
1229 // Unpack received (GID, PID) pairs into exportIDs resp. exportProcIDs.
1230 for (size_type i = 0; i < numExports; ++i) {
1231 exportGIDs[i] = static_cast<OrdinalType> (exportObjs[2*i]);
1232 exportProcIDs[i] = static_cast<int> (exportObjs[2*i+1]);
1233 }
1234 }
1235
1236 template <class OrdinalType>
1237 void Distributor::
1238 createFromRecvs (const Teuchos::ArrayView<const OrdinalType> &remoteGIDs,
1239 const Teuchos::ArrayView<const int> &remoteProcIDs,
1240 Teuchos::Array<OrdinalType> &exportGIDs,
1241 Teuchos::Array<int> &exportProcIDs)
1242 {
1243 using std::endl;
1244 const char errPrefix[] = "Tpetra::Distributor::createFromRecvs: ";
1245 const int myRank = plan_.getComm()->getRank();
1246
1247 std::unique_ptr<std::string> prefix;
1248 if (verbose_) {
1249 prefix = createPrefix("createFromRecvs");
1250 std::ostringstream os;
1251 os << *prefix << "Start" << endl;
1252 std::cerr << os.str();
1253 }
1254
1255 const bool debug = Details::Behavior::debug("Distributor");
1256 if (debug) {
1257 using Teuchos::outArg;
1258 using Teuchos::REDUCE_MAX;
1259 using Teuchos::reduceAll;
1260 // In debug mode, first test locally, then do an all-reduce to
1261 // make sure that all processes passed.
1262 const int errProc =
1263 (remoteGIDs.size () != remoteProcIDs.size ()) ? myRank : -1;
1264 int maxErrProc = -1;
1265 reduceAll(*plan_.getComm(), REDUCE_MAX, errProc, outArg(maxErrProc));
1266 TEUCHOS_TEST_FOR_EXCEPTION
1267 (maxErrProc != -1, std::runtime_error, errPrefix << "Lists "
1268 "of remote IDs and remote process IDs must have the same "
1269 "size on all participating processes. Maximum process ID "
1270 "with error: " << maxErrProc << ".");
1271 }
1272 else { // in non-debug mode, just test locally
1273 // NOTE (mfh 13 Feb 2020) This needs to throw std::runtime_error
1274 // in order to make an existing Distributor unit test pass.
1275 TEUCHOS_TEST_FOR_EXCEPTION
1276 (remoteGIDs.size() != remoteProcIDs.size(), std::runtime_error,
1277 errPrefix << "On Process " << myRank << ": "
1278 "remoteGIDs.size()=" << remoteGIDs.size() <<
1279 " != remoteProcIDs.size()=" << remoteProcIDs.size() << ".");
1280 }
1281
1282 computeSends(remoteGIDs, remoteProcIDs, exportGIDs, exportProcIDs);
1283
1284 plan_.createFromRecvs(remoteProcIDs);
1285
1286 if (verbose_) {
1287 std::ostringstream os;
1288 os << *prefix << "Done" << endl;
1289 std::cerr << os.str();
1290 }
1291 }
1292
1293} // namespace Tpetra
1294
1295#endif // TPETRA_DISTRIBUTOR_HPP
Declaration of Tpetra::Details::Behavior, a class that describes Tpetra's behavior.
Stand-alone utility functions and macros.
static bool debug()
Whether Tpetra is in debug mode.
Sets up and executes a communication plan for a Tpetra DistObject.
void doPostsAndWaits(const Teuchos::ArrayView< const Packet > &exports, size_t numPackets, const Teuchos::ArrayView< Packet > &imports)
Execute the (forward) communication plan.
void doReversePostsAndWaits(const Teuchos::ArrayView< const Packet > &exports, size_t numPackets, const Teuchos::ArrayView< Packet > &imports)
Execute the reverse communication plan.
const Details::DistributorPlan & getPlan() const
Get this Distributor's DistributorPlan.
size_t getMaxSendLength() const
Maximum number of values this process will send to another single process.
Teuchos::RCP< Distributor > getReverse(bool create=true) const
A reverse communication plan Distributor.
void createFromRecvs(const Teuchos::ArrayView< const Ordinal > &remoteIDs, const Teuchos::ArrayView< const int > &remoteProcIDs, Teuchos::Array< Ordinal > &exportIDs, Teuchos::Array< int > &exportProcIDs)
Set up Distributor using list of process ranks from which to receive.
Teuchos::ArrayView< const int > getProcsTo() const
Ranks of the processes to which this process will send values.
void doReversePosts(const Teuchos::ArrayRCP< const Packet > &exports, size_t numPackets, const Teuchos::ArrayRCP< Packet > &imports)
Post the data for a reverse plan, but do not execute the waits yet.
size_t getNumReceives() const
The number of processes from which we will receive data.
void doPosts(const Teuchos::ArrayRCP< const Packet > &exports, size_t numPackets, const Teuchos::ArrayRCP< Packet > &imports)
Post the data for a forward plan, but do not execute the waits yet.
void setParameterList(const Teuchos::RCP< Teuchos::ParameterList > &plist)
Set Distributor parameters.
size_t getTotalReceiveLength() const
Total number of values this process will receive from other processes.
virtual ~Distributor()=default
Destructor (virtual for memory safety).
bool hasSelfMessage() const
Whether the calling process will send or receive messages to itself.
void swap(Distributor &rhs)
Swap the contents of rhs with those of *this.
Teuchos::ArrayView< const size_t > getLengthsTo() const
Number of values this process will send to each process.
Teuchos::ArrayView< const int > getProcsFrom() const
Ranks of the processes sending values to this process.
Distributor(const Teuchos::RCP< const Teuchos::Comm< int > > &comm)
Construct using the specified communicator and default parameters.
std::string description() const
Return a one-line description of this object.
size_t createFromSends(const Teuchos::ArrayView< const int > &exportProcIDs)
Set up Distributor using list of process ranks to which this process will send.
void createFromSendsAndRecvs(const Teuchos::ArrayView< const int > &exportProcIDs, const Teuchos::ArrayView< const int > &remoteProcIDs)
Set up Distributor using list of process ranks to which to send, and list of process ranks from which...
Teuchos::RCP< const Teuchos::ParameterList > getValidParameters() const
List of valid Distributor parameters.
Teuchos::ArrayView< const size_t > getLengthsFrom() const
Number of values this process will receive from each process.
Details::EDistributorHowInitialized howInitialized() const
Return an enum indicating whether and how a Distributor was initialized.
size_t getNumSends() const
The number of processes to which we will send data.
void describe(Teuchos::FancyOStream &out, const Teuchos::EVerbosityLevel verbLevel=Teuchos::Describable::verbLevel_default) const
Describe this object in a human-readable way to the given output stream.
void getLastDoStatistics(size_t &bytes_sent, size_t &bytes_recvd) const
Information on the last call to do/doReverse.
EDistributorHowInitialized
Enum indicating how and whether a Distributor was initialized.
Namespace Tpetra contains the class and methods constituting the Tpetra library.
Teuchos::Array< std::string > distributorSendTypes()
Valid values for Distributor's "Send type" parameter.