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
32#if defined(TPETRA_ENABLE_DEPRECATED_CODE)
39[[deprecated]] Teuchos::Array<std::string> distributorSendTypes();
40#endif
41
104class Distributor : public Teuchos::Describable,
105 public Teuchos::ParameterListAcceptorDefaultBase {
106 public:
108
109
118 explicit Distributor(const Teuchos::RCP<const Teuchos::Comm<int> >& comm);
119
131 Distributor(const Teuchos::RCP<const Teuchos::Comm<int> >& comm,
132 const Teuchos::RCP<Teuchos::FancyOStream>& out);
133
147 Distributor(const Teuchos::RCP<const Teuchos::Comm<int> >& comm,
148 const Teuchos::RCP<Teuchos::ParameterList>& plist);
149
166 Distributor(const Teuchos::RCP<const Teuchos::Comm<int> >& comm,
167 const Teuchos::RCP<Teuchos::FancyOStream>& out,
168 const Teuchos::RCP<Teuchos::ParameterList>& plist);
169
172
177 virtual ~Distributor() = default;
178
184 void swap(Distributor& rhs);
185
187
189
194 void setParameterList(const Teuchos::RCP<Teuchos::ParameterList>& plist);
195
200 Teuchos::RCP<const Teuchos::ParameterList> getValidParameters() const;
201
203
205
225 size_t createFromSends(const Teuchos::ArrayView<const int>& exportProcIDs);
226
260 template <class Ordinal>
261 void
262 createFromRecvs(const Teuchos::ArrayView<const Ordinal>& remoteIDs,
263 const Teuchos::ArrayView<const int>& remoteProcIDs,
264 Teuchos::Array<Ordinal>& exportIDs,
265 Teuchos::Array<int>& exportProcIDs);
266
274 void
275 createFromSendsAndRecvs(const Teuchos::ArrayView<const int>& exportProcIDs,
276 const Teuchos::ArrayView<const int>& remoteProcIDs);
277
279
281
285 size_t getNumReceives() const;
286
290 size_t getNumSends() const;
291
293 bool hasSelfMessage() const;
294
296 size_t getMaxSendLength() const;
297
299 size_t getTotalReceiveLength() const;
300
305 Teuchos::ArrayView<const int> getProcsFrom() const;
306
311 Teuchos::ArrayView<const int> getProcsTo() const;
312
320 Teuchos::ArrayView<const size_t> getLengthsFrom() const;
321
329 Teuchos::ArrayView<const size_t> getLengthsTo() const;
330
336 return plan_.howInitialized();
337 }
338
340
342
353 Teuchos::RCP<Distributor> getReverse(bool create = true) const;
354
356
358
365 void doWaits();
366
373 void doReverseWaits();
374
395 template <class ExpView, class ImpView>
396 typename std::enable_if<(Kokkos::is_view<ExpView>::value && Kokkos::is_view<ImpView>::value)>::type
398 const ExpView& exports,
399 size_t numPackets,
400 const ImpView& imports);
401
423 template <class ExpView, class ImpView>
424 typename std::enable_if<(Kokkos::is_view<ExpView>::value && Kokkos::is_view<ImpView>::value)>::type
425 doPostsAndWaits(const ExpView& exports,
426 const Teuchos::ArrayView<const size_t>& numExportPacketsPerLID,
427 const ImpView& imports,
428 const Teuchos::ArrayView<const size_t>& numImportPacketsPerLID);
429
454 template <class ExpView, class ImpView>
455 typename std::enable_if<(Kokkos::is_view<ExpView>::value && Kokkos::is_view<ImpView>::value)>::type
456 doPosts(const ExpView& exports,
457 size_t numPackets,
458 const ImpView& imports);
459
478 template <class ExpView, class ImpView>
479 typename std::enable_if<(Kokkos::is_view<ExpView>::value && Kokkos::is_view<ImpView>::value)>::type
480 doPosts(const ExpView& exports,
481 const Teuchos::ArrayView<const size_t>& numExportPacketsPerLID,
482 const ImpView& imports,
483 const Teuchos::ArrayView<const size_t>& numImportPacketsPerLID);
484
489 template <class ExpView, class ImpView>
490 typename std::enable_if<(Kokkos::is_view<ExpView>::value && Kokkos::is_view<ImpView>::value)>::type
491 doReversePostsAndWaits(const ExpView& exports,
492 size_t numPackets,
493 const ImpView& imports);
494
499 template <class ExpView, class ImpView>
500 typename std::enable_if<(Kokkos::is_view<ExpView>::value && Kokkos::is_view<ImpView>::value)>::type
501 doReversePostsAndWaits(const ExpView& exports,
502 const Teuchos::ArrayView<const size_t>& numExportPacketsPerLID,
503 const ImpView& imports,
504 const Teuchos::ArrayView<const size_t>& numImportPacketsPerLID);
505
510 template <class ExpView, class ImpView>
511 typename std::enable_if<(Kokkos::is_view<ExpView>::value && Kokkos::is_view<ImpView>::value)>::type
512 doReversePosts(const ExpView& exports,
513 size_t numPackets,
514 const ImpView& imports);
515
520 template <class ExpView, class ImpView>
521 typename std::enable_if<(Kokkos::is_view<ExpView>::value && Kokkos::is_view<ImpView>::value)>::type
522 doReversePosts(const ExpView& exports,
523 const Teuchos::ArrayView<const size_t>& numExportPacketsPerLID,
524 const ImpView& imports,
525 const Teuchos::ArrayView<const size_t>& numImportPacketsPerLID);
526
528
530
532 std::string description() const;
533
555 void
556 describe(Teuchos::FancyOStream& out,
557 const Teuchos::EVerbosityLevel verbLevel =
558 Teuchos::Describable::verbLevel_default) const;
560
565 const Details::DistributorPlan& getPlan() const { return plan_; }
566
567 private:
569 Details::DistributorActor actor_;
570
572
573
575 static bool getVerbose();
576
581 std::unique_ptr<std::string>
582 createPrefix(const char methodName[]) const;
583
585 bool verbose_ = getVerbose();
587
592 mutable Teuchos::RCP<Distributor> reverseDistributor_;
593
606 template <class Ordinal>
607 void computeSends(const Teuchos::ArrayView<const Ordinal>& remoteGIDs,
608 const Teuchos::ArrayView<const int>& remoteProcIDs,
609 Teuchos::Array<Ordinal>& exportGIDs,
610 Teuchos::Array<int>& exportProcIDs);
611
613 void createReverseDistributor() const;
614
619 std::string
620 localDescribeToString(const Teuchos::EVerbosityLevel vl) const;
621}; // class Distributor
622
623template <class ExpView, class ImpView>
624typename std::enable_if<(Kokkos::is_view<ExpView>::value && Kokkos::is_view<ImpView>::value)>::type
626 doPostsAndWaits(const ExpView& exports,
628 const ImpView& imports) {
629 actor_.doPostsAndWaits(plan_, exports, numPackets, imports);
630}
631
632template <class ExpView, class ImpView>
633typename std::enable_if<(Kokkos::is_view<ExpView>::value && Kokkos::is_view<ImpView>::value)>::type
635 doPostsAndWaits(const ExpView& exports,
637 const ImpView& imports,
639 actor_.doPostsAndWaits(plan_, exports, numExportPacketsPerLID, imports, numImportPacketsPerLID);
640}
641
642template <class ExpView, class ImpView>
643typename std::enable_if<(Kokkos::is_view<ExpView>::value && Kokkos::is_view<ImpView>::value)>::type
645 doPosts(const ExpView& exports,
647 const ImpView& imports) {
648 actor_.doPosts(plan_, exports, numPackets, imports);
649}
650
651template <class ExpView, class ImpView>
652typename std::enable_if<(Kokkos::is_view<ExpView>::value && Kokkos::is_view<ImpView>::value)>::type
654 doPosts(const ExpView& exports,
656 const ImpView& imports,
658 actor_.doPosts(plan_, exports, numExportPacketsPerLID, imports, numImportPacketsPerLID);
659}
660
661template <class ExpView, class ImpView>
662typename std::enable_if<(Kokkos::is_view<ExpView>::value && Kokkos::is_view<ImpView>::value)>::type
664 doReversePostsAndWaits(const ExpView& exports,
666 const ImpView& imports) {
667 doReversePosts(exports, numPackets, imports);
668 doReverseWaits();
669}
670
671template <class ExpView, class ImpView>
672typename std::enable_if<(Kokkos::is_view<ExpView>::value && Kokkos::is_view<ImpView>::value)>::type
674 doReversePostsAndWaits(const ExpView& exports,
676 const ImpView& imports,
678 doReversePosts(exports, numExportPacketsPerLID, imports,
680 doReverseWaits();
681}
682
683template <class ExpView, class ImpView>
684typename std::enable_if<(Kokkos::is_view<ExpView>::value && Kokkos::is_view<ImpView>::value)>::type
686 doReversePosts(const ExpView& exports,
688 const ImpView& imports) {
689 // FIXME (mfh 29 Mar 2012) WHY?
691 !plan_.getIndicesTo().is_null(), std::runtime_error,
692 "Tpetra::Distributor::doReversePosts(3 args): Can only do "
693 "reverse communication when original data are blocked by process.");
694 if (reverseDistributor_.is_null()) {
695 createReverseDistributor();
696 }
697 reverseDistributor_->doPosts(exports, numPackets, imports);
698}
699
700template <class ExpView, class ImpView>
701typename std::enable_if<(Kokkos::is_view<ExpView>::value && Kokkos::is_view<ImpView>::value)>::type
703 doReversePosts(const ExpView& exports,
705 const ImpView& imports,
707 // FIXME (mfh 29 Mar 2012) WHY?
709 !plan_.getIndicesTo().is_null(), std::runtime_error,
710 "Tpetra::Distributor::doReversePosts(3 args): Can only do "
711 "reverse communication when original data are blocked by process.");
712 if (reverseDistributor_.is_null()) {
713 createReverseDistributor();
714 }
715 reverseDistributor_->doPosts(exports, numExportPacketsPerLID,
716 imports, numImportPacketsPerLID);
717}
718
719template <class OrdinalType>
720void Distributor::
721 computeSends(const Teuchos::ArrayView<const OrdinalType>& importGIDs,
722 const Teuchos::ArrayView<const int>& importProcIDs,
723 Teuchos::Array<OrdinalType>& exportGIDs,
724 Teuchos::Array<int>& exportProcIDs) {
725 // NOTE (mfh 19 Apr 2012): There was a note on this code saying:
726 // "assumes that size_t >= Ordinal". The code certainly does
727 // assume that sizeof(size_t) >= sizeof(OrdinalType) as well as
728 // sizeof(size_t) >= sizeof(int). This is because it casts the
729 // OrdinalType elements of importGIDs (along with their
730 // corresponding process IDs, as int) to size_t, and does a
731 // doPostsAndWaits<size_t>() to send the packed data.
732 using std::endl;
733 using Teuchos::ArrayView;
734 using size_type = typename ArrayView<const OrdinalType>::size_type;
735 const char errPrefix[] = "Tpetra::Distributor::computeSends: ";
736 const char suffix[] =
737 " Please report this bug to the Tpetra developers.";
738
739 const int myRank = plan_.getComm()->getRank();
740
742 std::invalid_argument, errPrefix << "On Process " << myRank << ": importProcIDs.size()=" << importProcIDs.size() << " != importGIDs.size()=" << importGIDs.size() << ".");
743
744 const size_type numImports = importProcIDs.size();
745 Kokkos::View<size_t*, Kokkos::HostSpace> importObjs("importObjs", 2 * numImports);
746 // Pack pairs (importGIDs[i], my process ID) to send into importObjs.
747 for (size_type i = 0; i < numImports; ++i) {
748 importObjs[2 * i] = static_cast<size_t>(importGIDs[i]);
749 importObjs[2 * i + 1] = static_cast<size_t>(myRank);
750 }
751 //
752 // Use a temporary Distributor to send the (importGIDs[i], myRank)
753 // pairs to importProcIDs[i].
754 //
755 Distributor tempPlan(plan_.getComm());
756 // mfh 20 Mar 2014: An extra-cautious cast from unsigned to
757 // signed, in order to forestall any possible causes for Bug 6069.
758 const size_t numExportsAsSizeT =
759 tempPlan.createFromSends(importProcIDs);
760 const size_type numExports =
761 static_cast<size_type>(numExportsAsSizeT);
762 TEUCHOS_TEST_FOR_EXCEPTION(numExports < 0, std::logic_error, errPrefix << "tempPlan.createFromSends() returned numExports=" << numExportsAsSizeT << " as a size_t, which overflows to " << numExports << " when cast to " << Teuchos::TypeNameTraits<size_type>::name() << "." << suffix);
763 TEUCHOS_TEST_FOR_EXCEPTION(size_type(tempPlan.getTotalReceiveLength()) != numExports,
764 std::logic_error, errPrefix << "tempPlan.getTotalReceiveLength()=" << tempPlan.getTotalReceiveLength() << " != numExports=" << numExports << "." << suffix);
765
766 if (numExports > 0) {
767 exportGIDs.resize(numExports);
768 exportProcIDs.resize(numExports);
769 }
770
771 // exportObjs: Packed receive buffer. (exportObjs[2*i],
772 // exportObjs[2*i+1]) will give the (GID, PID) pair for export i,
773 // after tempPlan.doPostsAndWaits(...) finishes below.
774 //
775 // FIXME (mfh 19 Mar 2014) This only works if OrdinalType fits in
776 // size_t. This issue might come up, for example, on a 32-bit
777 // machine using 64-bit global indices. I will add a check here
778 // for that case.
779 static_assert(sizeof(size_t) >= sizeof(OrdinalType),
780 "Tpetra::Distributor::computeSends: "
781 "sizeof(size_t) < sizeof(OrdinalType).");
782
783 TEUCHOS_TEST_FOR_EXCEPTION(tempPlan.getTotalReceiveLength() < size_t(numExports),
784 std::logic_error,
785 errPrefix << "tempPlan.getTotalReceiveLength()="
786 << tempPlan.getTotalReceiveLength() << " < numExports="
787 << numExports << "." << suffix);
788
789 Kokkos::View<size_t*, Kokkos::HostSpace> exportObjs("exportObjs", tempPlan.getTotalReceiveLength() * 2);
790 tempPlan.doPostsAndWaits(importObjs, 2, exportObjs);
791
792 // Unpack received (GID, PID) pairs into exportIDs resp. exportProcIDs.
793 for (size_type i = 0; i < numExports; ++i) {
794 exportGIDs[i] = static_cast<OrdinalType>(exportObjs[2 * i]);
795 exportProcIDs[i] = static_cast<int>(exportObjs[2 * i + 1]);
796 }
797
798 // Store tempPlan instead of recreating it later
799 plan_ = tempPlan.plan_;
800}
801
802template <class OrdinalType>
803void Distributor::
804 createFromRecvs(const Teuchos::ArrayView<const OrdinalType>& remoteGIDs,
805 const Teuchos::ArrayView<const int>& remoteProcIDs,
806 Teuchos::Array<OrdinalType>& exportGIDs,
807 Teuchos::Array<int>& exportProcIDs) {
808 using std::endl;
809 const char errPrefix[] = "Tpetra::Distributor::createFromRecvs: ";
810 const int myRank = plan_.getComm()->getRank();
811
812 std::unique_ptr<std::string> prefix;
813 if (verbose_) {
814 prefix = createPrefix("createFromRecvs");
815 std::ostringstream os;
816 os << *prefix << "Start" << endl;
817 std::cerr << os.str();
818 }
819
820 const bool debug = Details::Behavior::debug("Distributor");
821 if (debug) {
822 using Teuchos::outArg;
823 using Teuchos::REDUCE_MAX;
824 using Teuchos::reduceAll;
825 // In debug mode, first test locally, then do an all-reduce to
826 // make sure that all processes passed.
827 const int errProc =
828 (remoteGIDs.size() != remoteProcIDs.size()) ? myRank : -1;
829 int maxErrProc = -1;
830 reduceAll(*plan_.getComm(), REDUCE_MAX, errProc, outArg(maxErrProc));
831 TEUCHOS_TEST_FOR_EXCEPTION(maxErrProc != -1, std::runtime_error, errPrefix << "Lists "
832 "of remote IDs and remote process IDs must have the same "
833 "size on all participating processes. Maximum process ID "
834 "with error: "
835 << maxErrProc << ".");
836 } else { // in non-debug mode, just test locally
837 // NOTE (mfh 13 Feb 2020) This needs to throw std::runtime_error
838 // in order to make an existing Distributor unit test pass.
839 TEUCHOS_TEST_FOR_EXCEPTION(remoteGIDs.size() != remoteProcIDs.size(), std::runtime_error,
840 errPrefix << "On Process " << myRank << ": "
841 "remoteGIDs.size()="
842 << remoteGIDs.size() << " != remoteProcIDs.size()=" << remoteProcIDs.size() << ".");
843 }
844
845 computeSends(remoteGIDs, remoteProcIDs, exportGIDs, exportProcIDs);
846
847 plan_.createFromRecvs(remoteProcIDs);
848
849 if (verbose_) {
850 std::ostringstream os;
851 os << *prefix << "Done" << endl;
852 std::cerr << os.str();
853 }
854}
855
856} // namespace Tpetra
857
858#endif // TPETRA_DISTRIBUTOR_HPP
Declaration of Tpetra::Details::Behavior, a class that describes Tpetra's behavior.
Stand-alone utility functions and macros.
Struct that holds views of the contents of a CrsMatrix.
static bool debug()
Whether Tpetra is in debug mode.
Sets up and executes a communication plan for a Tpetra DistObject.
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.
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.
Teuchos::Array< std::string > distributorSendTypes()
Valid string values for Distributor's "Send type" parameter.
EDistributorHowInitialized
Enum indicating how and whether a Distributor was initialized.
Namespace Tpetra contains the class and methods constituting the Tpetra library.