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
94class Distributor : public Teuchos::Describable,
95 public Teuchos::ParameterListAcceptorDefaultBase {
96 public:
98
99
108 explicit Distributor(const Teuchos::RCP<const Teuchos::Comm<int> >& comm);
109
121 Distributor(const Teuchos::RCP<const Teuchos::Comm<int> >& comm,
122 const Teuchos::RCP<Teuchos::FancyOStream>& out);
123
137 Distributor(const Teuchos::RCP<const Teuchos::Comm<int> >& comm,
138 const Teuchos::RCP<Teuchos::ParameterList>& plist);
139
156 Distributor(const Teuchos::RCP<const Teuchos::Comm<int> >& comm,
157 const Teuchos::RCP<Teuchos::FancyOStream>& out,
158 const Teuchos::RCP<Teuchos::ParameterList>& plist);
159
162
167 virtual ~Distributor() = default;
168
174 void swap(Distributor& rhs);
175
177
179
184 void setParameterList(const Teuchos::RCP<Teuchos::ParameterList>& plist);
185
190 Teuchos::RCP<const Teuchos::ParameterList> getValidParameters() const;
191
193
195
215 size_t createFromSends(const Teuchos::ArrayView<const int>& exportProcIDs);
216
250 template <class Ordinal>
251 void
252 createFromRecvs(const Teuchos::ArrayView<const Ordinal>& remoteIDs,
253 const Teuchos::ArrayView<const int>& remoteProcIDs,
254 Teuchos::Array<Ordinal>& exportIDs,
255 Teuchos::Array<int>& exportProcIDs);
256
264 void
265 createFromSendsAndRecvs(const Teuchos::ArrayView<const int>& exportProcIDs,
266 const Teuchos::ArrayView<const int>& remoteProcIDs);
267
269
271
275 size_t getNumReceives() const;
276
280 size_t getNumSends() const;
281
283 bool hasSelfMessage() const;
284
286 size_t getMaxSendLength() const;
287
289 size_t getTotalReceiveLength() const;
290
295 Teuchos::ArrayView<const int> getProcsFrom() const;
296
301 Teuchos::ArrayView<const int> getProcsTo() const;
302
310 Teuchos::ArrayView<const size_t> getLengthsFrom() const;
311
319 Teuchos::ArrayView<const size_t> getLengthsTo() const;
320
326 return plan_.howInitialized();
327 }
328
330
332
343 Teuchos::RCP<Distributor> getReverse(bool create = true) const;
344
346
348
355 void doWaits();
356
363 void doReverseWaits();
364
385 template <class ExpView, class ImpView>
386 typename std::enable_if<(Kokkos::is_view<ExpView>::value && Kokkos::is_view<ImpView>::value)>::type
388 const ExpView& exports,
389 size_t numPackets,
390 const ImpView& imports);
391
413 template <class ExpView, class ImpView>
414 typename std::enable_if<(Kokkos::is_view<ExpView>::value && Kokkos::is_view<ImpView>::value)>::type
415 doPostsAndWaits(const ExpView& exports,
416 const Teuchos::ArrayView<const size_t>& numExportPacketsPerLID,
417 const ImpView& imports,
418 const Teuchos::ArrayView<const size_t>& numImportPacketsPerLID);
419
444 template <class ExpView, class ImpView>
445 typename std::enable_if<(Kokkos::is_view<ExpView>::value && Kokkos::is_view<ImpView>::value)>::type
446 doPosts(const ExpView& exports,
447 size_t numPackets,
448 const ImpView& imports);
449
468 template <class ExpView, class ImpView>
469 typename std::enable_if<(Kokkos::is_view<ExpView>::value && Kokkos::is_view<ImpView>::value)>::type
470 doPosts(const ExpView& exports,
471 const Teuchos::ArrayView<const size_t>& numExportPacketsPerLID,
472 const ImpView& imports,
473 const Teuchos::ArrayView<const size_t>& numImportPacketsPerLID);
474
479 template <class ExpView, class ImpView>
480 typename std::enable_if<(Kokkos::is_view<ExpView>::value && Kokkos::is_view<ImpView>::value)>::type
481 doReversePostsAndWaits(const ExpView& exports,
482 size_t numPackets,
483 const ImpView& imports);
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 const Teuchos::ArrayView<const size_t>& numExportPacketsPerLID,
493 const ImpView& imports,
494 const Teuchos::ArrayView<const size_t>& numImportPacketsPerLID);
495
500 template <class ExpView, class ImpView>
501 typename std::enable_if<(Kokkos::is_view<ExpView>::value && Kokkos::is_view<ImpView>::value)>::type
502 doReversePosts(const ExpView& exports,
503 size_t numPackets,
504 const ImpView& imports);
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 const Teuchos::ArrayView<const size_t>& numExportPacketsPerLID,
514 const ImpView& imports,
515 const Teuchos::ArrayView<const size_t>& numImportPacketsPerLID);
516
518
520
522 std::string description() const;
523
545 void
546 describe(Teuchos::FancyOStream& out,
547 const Teuchos::EVerbosityLevel verbLevel =
548 Teuchos::Describable::verbLevel_default) const;
550
555 const Details::DistributorPlan& getPlan() const { return plan_; }
556
557 private:
559 Details::DistributorActor actor_;
560
562
563
565 static bool getVerbose();
566
571 std::unique_ptr<std::string>
572 createPrefix(const char methodName[]) const;
573
575 bool verbose_ = getVerbose();
577
582 mutable Teuchos::RCP<Distributor> reverseDistributor_;
583
596 template <class Ordinal>
597 void computeSends(const Teuchos::ArrayView<const Ordinal>& remoteGIDs,
598 const Teuchos::ArrayView<const int>& remoteProcIDs,
599 Teuchos::Array<Ordinal>& exportGIDs,
600 Teuchos::Array<int>& exportProcIDs);
601
603 void createReverseDistributor() const;
604
609 std::string
610 localDescribeToString(const Teuchos::EVerbosityLevel vl) const;
611}; // class Distributor
612
613template <class ExpView, class ImpView>
614typename std::enable_if<(Kokkos::is_view<ExpView>::value && Kokkos::is_view<ImpView>::value)>::type
616 doPostsAndWaits(const ExpView& exports,
618 const ImpView& imports) {
619 actor_.doPostsAndWaits(plan_, exports, numPackets, imports);
620}
621
622template <class ExpView, class ImpView>
623typename std::enable_if<(Kokkos::is_view<ExpView>::value && Kokkos::is_view<ImpView>::value)>::type
625 doPostsAndWaits(const ExpView& exports,
627 const ImpView& imports,
629 actor_.doPostsAndWaits(plan_, exports, numExportPacketsPerLID, imports, numImportPacketsPerLID);
630}
631
632template <class ExpView, class ImpView>
633typename std::enable_if<(Kokkos::is_view<ExpView>::value && Kokkos::is_view<ImpView>::value)>::type
635 doPosts(const ExpView& exports,
637 const ImpView& imports) {
638 actor_.doPosts(plan_, exports, numPackets, imports);
639}
640
641template <class ExpView, class ImpView>
642typename std::enable_if<(Kokkos::is_view<ExpView>::value && Kokkos::is_view<ImpView>::value)>::type
644 doPosts(const ExpView& exports,
646 const ImpView& imports,
648 actor_.doPosts(plan_, exports, numExportPacketsPerLID, imports, numImportPacketsPerLID);
649}
650
651template <class ExpView, class ImpView>
652typename std::enable_if<(Kokkos::is_view<ExpView>::value && Kokkos::is_view<ImpView>::value)>::type
654 doReversePostsAndWaits(const ExpView& exports,
656 const ImpView& imports) {
657 doReversePosts(exports, numPackets, imports);
658 doReverseWaits();
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,
668 doReversePosts(exports, numExportPacketsPerLID, imports,
670 doReverseWaits();
671}
672
673template <class ExpView, class ImpView>
674typename std::enable_if<(Kokkos::is_view<ExpView>::value && Kokkos::is_view<ImpView>::value)>::type
676 doReversePosts(const ExpView& exports,
678 const ImpView& imports) {
679 // FIXME (mfh 29 Mar 2012) WHY?
681 !plan_.getIndicesTo().is_null(), std::runtime_error,
682 "Tpetra::Distributor::doReversePosts(3 args): Can only do "
683 "reverse communication when original data are blocked by process.");
684 if (reverseDistributor_.is_null()) {
685 createReverseDistributor();
686 }
687 reverseDistributor_->doPosts(exports, numPackets, imports);
688}
689
690template <class ExpView, class ImpView>
691typename std::enable_if<(Kokkos::is_view<ExpView>::value && Kokkos::is_view<ImpView>::value)>::type
693 doReversePosts(const ExpView& exports,
695 const ImpView& imports,
697 // FIXME (mfh 29 Mar 2012) WHY?
699 !plan_.getIndicesTo().is_null(), std::runtime_error,
700 "Tpetra::Distributor::doReversePosts(3 args): Can only do "
701 "reverse communication when original data are blocked by process.");
702 if (reverseDistributor_.is_null()) {
703 createReverseDistributor();
704 }
705 reverseDistributor_->doPosts(exports, numExportPacketsPerLID,
706 imports, numImportPacketsPerLID);
707}
708
709template <class OrdinalType>
710void Distributor::
711 computeSends(const Teuchos::ArrayView<const OrdinalType>& importGIDs,
712 const Teuchos::ArrayView<const int>& importProcIDs,
713 Teuchos::Array<OrdinalType>& exportGIDs,
714 Teuchos::Array<int>& exportProcIDs) {
715 // NOTE (mfh 19 Apr 2012): There was a note on this code saying:
716 // "assumes that size_t >= Ordinal". The code certainly does
717 // assume that sizeof(size_t) >= sizeof(OrdinalType) as well as
718 // sizeof(size_t) >= sizeof(int). This is because it casts the
719 // OrdinalType elements of importGIDs (along with their
720 // corresponding process IDs, as int) to size_t, and does a
721 // doPostsAndWaits<size_t>() to send the packed data.
722 using std::endl;
723 using Teuchos::ArrayView;
724 using size_type = typename ArrayView<const OrdinalType>::size_type;
725 const char errPrefix[] = "Tpetra::Distributor::computeSends: ";
726 const char suffix[] =
727 " Please report this bug to the Tpetra developers.";
728
729 const int myRank = plan_.getComm()->getRank();
730
732 std::invalid_argument, errPrefix << "On Process " << myRank << ": importProcIDs.size()=" << importProcIDs.size() << " != importGIDs.size()=" << importGIDs.size() << ".");
733
734 const size_type numImports = importProcIDs.size();
735 Kokkos::View<size_t*, Kokkos::HostSpace> importObjs("importObjs", 2 * numImports);
736 // Pack pairs (importGIDs[i], my process ID) to send into importObjs.
737 for (size_type i = 0; i < numImports; ++i) {
738 importObjs[2 * i] = static_cast<size_t>(importGIDs[i]);
739 importObjs[2 * i + 1] = static_cast<size_t>(myRank);
740 }
741 //
742 // Use a temporary Distributor to send the (importGIDs[i], myRank)
743 // pairs to importProcIDs[i].
744 //
745 Distributor tempPlan(plan_.getComm());
746 // mfh 20 Mar 2014: An extra-cautious cast from unsigned to
747 // signed, in order to forestall any possible causes for Bug 6069.
748 const size_t numExportsAsSizeT =
749 tempPlan.createFromSends(importProcIDs);
750 const size_type numExports =
751 static_cast<size_type>(numExportsAsSizeT);
752 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);
753 TEUCHOS_TEST_FOR_EXCEPTION(size_type(tempPlan.getTotalReceiveLength()) != numExports,
754 std::logic_error, errPrefix << "tempPlan.getTotalReceiveLength()=" << tempPlan.getTotalReceiveLength() << " != numExports=" << numExports << "." << suffix);
755
756 if (numExports > 0) {
757 exportGIDs.resize(numExports);
758 exportProcIDs.resize(numExports);
759 }
760
761 // exportObjs: Packed receive buffer. (exportObjs[2*i],
762 // exportObjs[2*i+1]) will give the (GID, PID) pair for export i,
763 // after tempPlan.doPostsAndWaits(...) finishes below.
764 //
765 // FIXME (mfh 19 Mar 2014) This only works if OrdinalType fits in
766 // size_t. This issue might come up, for example, on a 32-bit
767 // machine using 64-bit global indices. I will add a check here
768 // for that case.
769 static_assert(sizeof(size_t) >= sizeof(OrdinalType),
770 "Tpetra::Distributor::computeSends: "
771 "sizeof(size_t) < sizeof(OrdinalType).");
772
773 TEUCHOS_TEST_FOR_EXCEPTION(tempPlan.getTotalReceiveLength() < size_t(numExports),
774 std::logic_error,
775 errPrefix << "tempPlan.getTotalReceiveLength()="
776 << tempPlan.getTotalReceiveLength() << " < numExports="
777 << numExports << "." << suffix);
778
779 Kokkos::View<size_t*, Kokkos::HostSpace> exportObjs("exportObjs", tempPlan.getTotalReceiveLength() * 2);
780 tempPlan.doPostsAndWaits(importObjs, 2, exportObjs);
781
782 // Unpack received (GID, PID) pairs into exportIDs resp. exportProcIDs.
783 for (size_type i = 0; i < numExports; ++i) {
784 exportGIDs[i] = static_cast<OrdinalType>(exportObjs[2 * i]);
785 exportProcIDs[i] = static_cast<int>(exportObjs[2 * i + 1]);
786 }
787
788 // Store tempPlan instead of recreating it later
789 plan_ = tempPlan.plan_;
790}
791
792template <class OrdinalType>
793void Distributor::
794 createFromRecvs(const Teuchos::ArrayView<const OrdinalType>& remoteGIDs,
795 const Teuchos::ArrayView<const int>& remoteProcIDs,
796 Teuchos::Array<OrdinalType>& exportGIDs,
797 Teuchos::Array<int>& exportProcIDs) {
798 using std::endl;
799 const char errPrefix[] = "Tpetra::Distributor::createFromRecvs: ";
800 const int myRank = plan_.getComm()->getRank();
801
802 std::unique_ptr<std::string> prefix;
803 if (verbose_) {
804 prefix = createPrefix("createFromRecvs");
805 std::ostringstream os;
806 os << *prefix << "Start" << endl;
807 std::cerr << os.str();
808 }
809
810 const bool debug = Details::Behavior::debug("Distributor");
811 if (debug) {
812 using Teuchos::outArg;
813 using Teuchos::REDUCE_MAX;
814 using Teuchos::reduceAll;
815 // In debug mode, first test locally, then do an all-reduce to
816 // make sure that all processes passed.
817 const int errProc =
818 (remoteGIDs.size() != remoteProcIDs.size()) ? myRank : -1;
819 int maxErrProc = -1;
820 reduceAll(*plan_.getComm(), REDUCE_MAX, errProc, outArg(maxErrProc));
821 TEUCHOS_TEST_FOR_EXCEPTION(maxErrProc != -1, std::runtime_error, errPrefix << "Lists "
822 "of remote IDs and remote process IDs must have the same "
823 "size on all participating processes. Maximum process ID "
824 "with error: "
825 << maxErrProc << ".");
826 } else { // in non-debug mode, just test locally
827 // NOTE (mfh 13 Feb 2020) This needs to throw std::runtime_error
828 // in order to make an existing Distributor unit test pass.
829 TEUCHOS_TEST_FOR_EXCEPTION(remoteGIDs.size() != remoteProcIDs.size(), std::runtime_error,
830 errPrefix << "On Process " << myRank << ": "
831 "remoteGIDs.size()="
832 << remoteGIDs.size() << " != remoteProcIDs.size()=" << remoteProcIDs.size() << ".");
833 }
834
835 computeSends(remoteGIDs, remoteProcIDs, exportGIDs, exportProcIDs);
836
837 plan_.createFromRecvs(remoteProcIDs);
838
839 if (verbose_) {
840 std::ostringstream os;
841 os << *prefix << "Done" << endl;
842 std::cerr << os.str();
843 }
844}
845
846} // namespace Tpetra
847
848#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.
EDistributorHowInitialized
Enum indicating how and whether a Distributor was initialized.
Namespace Tpetra contains the class and methods constituting the Tpetra library.