Tpetra parallel linear algebra Version of the Day
Loading...
Searching...
No Matches
Tpetra_Distributor.hpp
1// @HEADER
2// *****************************************************************************
3// Tpetra: Templated Linear Algebra Services Package
4//
5// Copyright 2008 NTESS and the Tpetra contributors.
6// SPDX-License-Identifier: BSD-3-Clause
7// *****************************************************************************
8// @HEADER
9
10#ifndef TPETRA_DISTRIBUTOR_HPP
11#define TPETRA_DISTRIBUTOR_HPP
12
13#include "Tpetra_Details_DistributorActor.hpp"
15
16#include "Tpetra_Util.hpp"
17#include "Teuchos_as.hpp"
18#include "Teuchos_Describable.hpp"
19#include "Teuchos_ParameterListAcceptorDefaultBase.hpp"
20#include "Teuchos_VerboseObject.hpp"
22
23#include "KokkosCompat_View.hpp"
24#include "Kokkos_Core.hpp"
25#include "Kokkos_TeuchosCommAdapters.hpp"
26#include <memory>
27#include <sstream>
28#include <type_traits>
29
30namespace Tpetra {
31
38 Teuchos::Array<std::string> distributorSendTypes ();
39
103 public Teuchos::Describable,
104 public Teuchos::ParameterListAcceptorDefaultBase {
105 public:
107
108
117 explicit Distributor (const Teuchos::RCP<const Teuchos::Comm<int> >& comm);
118
130 Distributor (const Teuchos::RCP<const Teuchos::Comm<int> >& comm,
131 const Teuchos::RCP<Teuchos::FancyOStream>& out);
132
146 Distributor (const Teuchos::RCP<const Teuchos::Comm<int> >& comm,
147 const Teuchos::RCP<Teuchos::ParameterList>& plist);
148
165 Distributor (const Teuchos::RCP<const Teuchos::Comm<int> >& comm,
166 const Teuchos::RCP<Teuchos::FancyOStream>& out,
167 const Teuchos::RCP<Teuchos::ParameterList>& plist);
168
170 Distributor (const Distributor& distributor);
171
176 virtual ~Distributor () = default;
177
183 void swap (Distributor& rhs);
184
186
188
193 void setParameterList (const Teuchos::RCP<Teuchos::ParameterList>& plist);
194
199 Teuchos::RCP<const Teuchos::ParameterList> getValidParameters () const;
200
202
204
224 size_t createFromSends (const Teuchos::ArrayView<const int>& exportProcIDs);
225
259 template <class Ordinal>
260 void
261 createFromRecvs (const Teuchos::ArrayView<const Ordinal>& remoteIDs,
262 const Teuchos::ArrayView<const int>& remoteProcIDs,
263 Teuchos::Array<Ordinal>& exportIDs,
264 Teuchos::Array<int>& exportProcIDs);
265
273 void
274 createFromSendsAndRecvs (const Teuchos::ArrayView<const int>& exportProcIDs,
275 const Teuchos::ArrayView<const int>& remoteProcIDs);
276
278
280
284 size_t getNumReceives() const;
285
289 size_t getNumSends() const;
290
292 bool hasSelfMessage() const;
293
295 size_t getMaxSendLength() const;
296
298 size_t getTotalReceiveLength() const;
299
304 Teuchos::ArrayView<const int> getProcsFrom() const;
305
310 Teuchos::ArrayView<const int> getProcsTo() const;
311
319 Teuchos::ArrayView<const size_t> getLengthsFrom() const;
320
328 Teuchos::ArrayView<const size_t> getLengthsTo() const;
329
335 return plan_.howInitialized();
336 }
337
339
341
352 Teuchos::RCP<Distributor> getReverse(bool create=true) const;
353
355
357
364 void doWaits ();
365
372 void doReverseWaits ();
373
394 template <class ExpView, class ImpView>
395 typename std::enable_if<(Kokkos::is_view<ExpView>::value && Kokkos::is_view<ImpView>::value)>::type
397 const ExpView &exports,
398 size_t numPackets,
399 const ImpView &imports);
400
422 template <class ExpView, class ImpView>
423 typename std::enable_if<(Kokkos::is_view<ExpView>::value && Kokkos::is_view<ImpView>::value)>::type
424 doPostsAndWaits (const ExpView &exports,
425 const Teuchos::ArrayView<const size_t>& numExportPacketsPerLID,
426 const ImpView &imports,
427 const Teuchos::ArrayView<const size_t>& numImportPacketsPerLID);
428
453 template <class ExpView, class ImpView>
454 typename std::enable_if<(Kokkos::is_view<ExpView>::value && Kokkos::is_view<ImpView>::value)>::type
455 doPosts (const ExpView &exports,
456 size_t numPackets,
457 const ImpView &imports);
458
477 template <class ExpView, class ImpView>
478 typename std::enable_if<(Kokkos::is_view<ExpView>::value && Kokkos::is_view<ImpView>::value)>::type
479 doPosts (const ExpView &exports,
480 const Teuchos::ArrayView<const size_t>& numExportPacketsPerLID,
481 const ImpView &imports,
482 const Teuchos::ArrayView<const size_t>& numImportPacketsPerLID);
483
488 template <class ExpView, class ImpView>
489 typename std::enable_if<(Kokkos::is_view<ExpView>::value && Kokkos::is_view<ImpView>::value)>::type
490 doReversePostsAndWaits (const ExpView &exports,
491 size_t numPackets,
492 const ImpView &imports);
493
498 template <class ExpView, class ImpView>
499 typename std::enable_if<(Kokkos::is_view<ExpView>::value && Kokkos::is_view<ImpView>::value)>::type
500 doReversePostsAndWaits (const ExpView &exports,
501 const Teuchos::ArrayView<const size_t>& numExportPacketsPerLID,
502 const ImpView &imports,
503 const Teuchos::ArrayView<const size_t>& numImportPacketsPerLID);
504
509 template <class ExpView, class ImpView>
510 typename std::enable_if<(Kokkos::is_view<ExpView>::value && Kokkos::is_view<ImpView>::value)>::type
511 doReversePosts (const ExpView &exports,
512 size_t numPackets,
513 const ImpView &imports);
514
519 template <class ExpView, class ImpView>
520 typename std::enable_if<(Kokkos::is_view<ExpView>::value && Kokkos::is_view<ImpView>::value)>::type
521 doReversePosts (const ExpView &exports,
522 const Teuchos::ArrayView<const size_t>& numExportPacketsPerLID,
523 const ImpView &imports,
524 const Teuchos::ArrayView<const size_t>& numImportPacketsPerLID);
525
527
529
531 std::string description() const;
532
554 void
555 describe (Teuchos::FancyOStream& out,
556 const Teuchos::EVerbosityLevel verbLevel =
557 Teuchos::Describable::verbLevel_default) const;
559
564 const Details::DistributorPlan& getPlan() const { return plan_; }
565 private:
567 Details::DistributorActor actor_;
568
570
571
573 static bool getVerbose();
574
579 std::unique_ptr<std::string>
580 createPrefix(const char methodName[]) const;
581
583 bool verbose_ = getVerbose();
585
590 mutable Teuchos::RCP<Distributor> reverseDistributor_;
591
604 template <class Ordinal>
605 void computeSends (const Teuchos::ArrayView<const Ordinal> &remoteGIDs,
606 const Teuchos::ArrayView<const int> &remoteProcIDs,
607 Teuchos::Array<Ordinal> &exportGIDs,
608 Teuchos::Array<int> &exportProcIDs);
609
611 void createReverseDistributor() const;
612
613
618 std::string
619 localDescribeToString (const Teuchos::EVerbosityLevel vl) const;
620 }; // class Distributor
621
622 template <class ExpView, class ImpView>
623 typename std::enable_if<(Kokkos::is_view<ExpView>::value && Kokkos::is_view<ImpView>::value)>::type
625 doPostsAndWaits (const ExpView& exports,
626 size_t numPackets,
627 const ImpView& imports)
628 {
629 actor_.doPostsAndWaits(plan_, exports, numPackets, imports);
630 }
631
632 template <class ExpView, class ImpView>
633 typename std::enable_if<(Kokkos::is_view<ExpView>::value && Kokkos::is_view<ImpView>::value)>::type
635 doPostsAndWaits(const ExpView& exports,
636 const Teuchos::ArrayView<const size_t>& numExportPacketsPerLID,
637 const ImpView& imports,
638 const Teuchos::ArrayView<const size_t>& numImportPacketsPerLID)
639 {
640 actor_.doPostsAndWaits(plan_, exports, numExportPacketsPerLID, imports, numImportPacketsPerLID);
641 }
642
643
644 template <class ExpView, class ImpView>
645 typename std::enable_if<(Kokkos::is_view<ExpView>::value && Kokkos::is_view<ImpView>::value)>::type
647 doPosts (const ExpView &exports,
648 size_t numPackets,
649 const ImpView &imports)
650 {
651 actor_.doPosts(plan_, exports, numPackets, imports);
652 }
653
654 template <class ExpView, class ImpView>
655 typename std::enable_if<(Kokkos::is_view<ExpView>::value && Kokkos::is_view<ImpView>::value)>::type
657 doPosts (const ExpView &exports,
658 const Teuchos::ArrayView<const size_t>& numExportPacketsPerLID,
659 const ImpView &imports,
660 const Teuchos::ArrayView<const size_t>& numImportPacketsPerLID)
661 {
662 actor_.doPosts(plan_, exports, numExportPacketsPerLID, imports, numImportPacketsPerLID);
663 }
664
665 template <class ExpView, class ImpView>
666 typename std::enable_if<(Kokkos::is_view<ExpView>::value && Kokkos::is_view<ImpView>::value)>::type
668 doReversePostsAndWaits (const ExpView& exports,
669 size_t numPackets,
670 const ImpView& imports)
671 {
672 doReversePosts (exports, numPackets, imports);
674 }
675
676 template <class ExpView, class ImpView>
677 typename std::enable_if<(Kokkos::is_view<ExpView>::value && Kokkos::is_view<ImpView>::value)>::type
679 doReversePostsAndWaits (const ExpView& exports,
680 const Teuchos::ArrayView<const size_t>& numExportPacketsPerLID,
681 const ImpView& imports,
682 const Teuchos::ArrayView<const size_t>& numImportPacketsPerLID)
683 {
684 doReversePosts (exports, numExportPacketsPerLID, imports,
685 numImportPacketsPerLID);
687 }
688
689 template <class ExpView, class ImpView>
690 typename std::enable_if<(Kokkos::is_view<ExpView>::value && Kokkos::is_view<ImpView>::value)>::type
692 doReversePosts (const ExpView &exports,
693 size_t numPackets,
694 const ImpView &imports)
695 {
696 // FIXME (mfh 29 Mar 2012) WHY?
697 TEUCHOS_TEST_FOR_EXCEPTION(
698 ! plan_.getIndicesTo().is_null(), std::runtime_error,
699 "Tpetra::Distributor::doReversePosts(3 args): Can only do "
700 "reverse communication when original data are blocked by process.");
701 if (reverseDistributor_.is_null ()) {
702 createReverseDistributor ();
703 }
704 reverseDistributor_->doPosts (exports, numPackets, imports);
705 }
706
707 template <class ExpView, class ImpView>
708 typename std::enable_if<(Kokkos::is_view<ExpView>::value && Kokkos::is_view<ImpView>::value)>::type
710 doReversePosts (const ExpView &exports,
711 const Teuchos::ArrayView<const size_t>& numExportPacketsPerLID,
712 const ImpView &imports,
713 const Teuchos::ArrayView<const size_t>& numImportPacketsPerLID)
714 {
715 // FIXME (mfh 29 Mar 2012) WHY?
716 TEUCHOS_TEST_FOR_EXCEPTION(
717 ! plan_.getIndicesTo().is_null(), std::runtime_error,
718 "Tpetra::Distributor::doReversePosts(3 args): Can only do "
719 "reverse communication when original data are blocked by process.");
720 if (reverseDistributor_.is_null ()) {
721 createReverseDistributor ();
722 }
723 reverseDistributor_->doPosts (exports, numExportPacketsPerLID,
724 imports, numImportPacketsPerLID);
725 }
726
727 template <class OrdinalType>
728 void Distributor::
729 computeSends(const Teuchos::ArrayView<const OrdinalType>& importGIDs,
730 const Teuchos::ArrayView<const int>& importProcIDs,
731 Teuchos::Array<OrdinalType>& exportGIDs,
732 Teuchos::Array<int>& exportProcIDs)
733 {
734 // NOTE (mfh 19 Apr 2012): There was a note on this code saying:
735 // "assumes that size_t >= Ordinal". The code certainly does
736 // assume that sizeof(size_t) >= sizeof(OrdinalType) as well as
737 // sizeof(size_t) >= sizeof(int). This is because it casts the
738 // OrdinalType elements of importGIDs (along with their
739 // corresponding process IDs, as int) to size_t, and does a
740 // doPostsAndWaits<size_t>() to send the packed data.
741 using Teuchos::ArrayView;
742 using std::endl;
743 using size_type = typename ArrayView<const OrdinalType>::size_type;
744 const char errPrefix[] = "Tpetra::Distributor::computeSends: ";
745 const char suffix[] =
746 " Please report this bug to the Tpetra developers.";
747
748 const int myRank = plan_.getComm()->getRank ();
749
750 TEUCHOS_TEST_FOR_EXCEPTION
751 (importGIDs.size () != importProcIDs.size (),
752 std::invalid_argument, errPrefix << "On Process " << myRank
753 << ": importProcIDs.size()=" << importProcIDs.size()
754 << " != importGIDs.size()=" << importGIDs.size() << ".");
755
756 const size_type numImports = importProcIDs.size();
757 Kokkos::View<size_t*, Kokkos::HostSpace> importObjs("importObjs", 2*numImports);
758 // Pack pairs (importGIDs[i], my process ID) to send into importObjs.
759 for (size_type i = 0; i < numImports; ++i) {
760 importObjs[2*i] = static_cast<size_t>(importGIDs[i]);
761 importObjs[2*i+1] = static_cast<size_t>(myRank);
762 }
763 //
764 // Use a temporary Distributor to send the (importGIDs[i], myRank)
765 // pairs to importProcIDs[i].
766 //
767 Distributor tempPlan(plan_.getComm());
768 // mfh 20 Mar 2014: An extra-cautious cast from unsigned to
769 // signed, in order to forestall any possible causes for Bug 6069.
770 const size_t numExportsAsSizeT =
771 tempPlan.createFromSends(importProcIDs);
772 const size_type numExports =
773 static_cast<size_type>(numExportsAsSizeT);
774 TEUCHOS_TEST_FOR_EXCEPTION
775 (numExports < 0, std::logic_error, errPrefix <<
776 "tempPlan.createFromSends() returned numExports="
777 << numExportsAsSizeT << " as a size_t, which overflows to "
778 << numExports << " when cast to " <<
779 Teuchos::TypeNameTraits<size_type>::name () << "." << suffix);
780 TEUCHOS_TEST_FOR_EXCEPTION
781 (size_type(tempPlan.getTotalReceiveLength()) != numExports,
782 std::logic_error, errPrefix << "tempPlan.getTotalReceiveLength()="
783 << tempPlan.getTotalReceiveLength () << " != numExports="
784 << numExports << "." << suffix);
785
786 if (numExports > 0) {
787 exportGIDs.resize(numExports);
788 exportProcIDs.resize(numExports);
789 }
790
791 // exportObjs: Packed receive buffer. (exportObjs[2*i],
792 // exportObjs[2*i+1]) will give the (GID, PID) pair for export i,
793 // after tempPlan.doPostsAndWaits(...) finishes below.
794 //
795 // FIXME (mfh 19 Mar 2014) This only works if OrdinalType fits in
796 // size_t. This issue might come up, for example, on a 32-bit
797 // machine using 64-bit global indices. I will add a check here
798 // for that case.
799 static_assert(sizeof(size_t) >= sizeof(OrdinalType),
800 "Tpetra::Distributor::computeSends: "
801 "sizeof(size_t) < sizeof(OrdinalType).");
802
803 TEUCHOS_TEST_FOR_EXCEPTION
804 (tempPlan.getTotalReceiveLength () < size_t(numExports),
805 std::logic_error,
806 errPrefix << "tempPlan.getTotalReceiveLength()="
807 << tempPlan.getTotalReceiveLength() << " < numExports="
808 << numExports << "." << suffix);
809
810 Kokkos::View<size_t*, Kokkos::HostSpace> exportObjs("exportObjs", tempPlan.getTotalReceiveLength() * 2);
811 tempPlan.doPostsAndWaits(importObjs, 2, exportObjs);
812
813 // Unpack received (GID, PID) pairs into exportIDs resp. exportProcIDs.
814 for (size_type i = 0; i < numExports; ++i) {
815 exportGIDs[i] = static_cast<OrdinalType> (exportObjs[2*i]);
816 exportProcIDs[i] = static_cast<int> (exportObjs[2*i+1]);
817 }
818 }
819
820 template <class OrdinalType>
821 void Distributor::
822 createFromRecvs (const Teuchos::ArrayView<const OrdinalType> &remoteGIDs,
823 const Teuchos::ArrayView<const int> &remoteProcIDs,
824 Teuchos::Array<OrdinalType> &exportGIDs,
825 Teuchos::Array<int> &exportProcIDs)
826 {
827 using std::endl;
828 const char errPrefix[] = "Tpetra::Distributor::createFromRecvs: ";
829 const int myRank = plan_.getComm()->getRank();
830
831 std::unique_ptr<std::string> prefix;
832 if (verbose_) {
833 prefix = createPrefix("createFromRecvs");
834 std::ostringstream os;
835 os << *prefix << "Start" << endl;
836 std::cerr << os.str();
837 }
838
839 const bool debug = Details::Behavior::debug("Distributor");
840 if (debug) {
841 using Teuchos::outArg;
842 using Teuchos::REDUCE_MAX;
843 using Teuchos::reduceAll;
844 // In debug mode, first test locally, then do an all-reduce to
845 // make sure that all processes passed.
846 const int errProc =
847 (remoteGIDs.size () != remoteProcIDs.size ()) ? myRank : -1;
848 int maxErrProc = -1;
849 reduceAll(*plan_.getComm(), REDUCE_MAX, errProc, outArg(maxErrProc));
850 TEUCHOS_TEST_FOR_EXCEPTION
851 (maxErrProc != -1, std::runtime_error, errPrefix << "Lists "
852 "of remote IDs and remote process IDs must have the same "
853 "size on all participating processes. Maximum process ID "
854 "with error: " << maxErrProc << ".");
855 }
856 else { // in non-debug mode, just test locally
857 // NOTE (mfh 13 Feb 2020) This needs to throw std::runtime_error
858 // in order to make an existing Distributor unit test pass.
859 TEUCHOS_TEST_FOR_EXCEPTION
860 (remoteGIDs.size() != remoteProcIDs.size(), std::runtime_error,
861 errPrefix << "On Process " << myRank << ": "
862 "remoteGIDs.size()=" << remoteGIDs.size() <<
863 " != remoteProcIDs.size()=" << remoteProcIDs.size() << ".");
864 }
865
866 computeSends(remoteGIDs, remoteProcIDs, exportGIDs, exportProcIDs);
867
868 plan_.createFromRecvs(remoteProcIDs);
869
870 if (verbose_) {
871 std::ostringstream os;
872 os << *prefix << "Done" << endl;
873 std::cerr << os.str();
874 }
875 }
876
877} // namespace Tpetra
878
879#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.
std::enable_if<(Kokkos::is_view< ExpView >::value &&Kokkos::is_view< ImpView >::value)>::type doPosts(const ExpView &exports, size_t numPackets, const ImpView &imports)
Post the data for a forward plan, but do not execute the waits yet.
std::enable_if<(Kokkos::is_view< ExpView >::value &&Kokkos::is_view< ImpView >::value)>::type doPostsAndWaits(const ExpView &exports, size_t numPackets, const ImpView &imports)
Execute the (forward) 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.
size_t getNumReceives() const
The number of processes from which we will receive data.
std::enable_if<(Kokkos::is_view< ExpView >::value &&Kokkos::is_view< ImpView >::value)>::type doReversePostsAndWaits(const ExpView &exports, size_t numPackets, const ImpView &imports)
Execute the reverse communication plan.
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.
std::enable_if<(Kokkos::is_view< ExpView >::value &&Kokkos::is_view< ImpView >::value)>::type doReversePosts(const ExpView &exports, size_t numPackets, const ImpView &imports)
Post the data for a reverse plan, but do not execute the waits yet.
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.
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.