Tpetra parallel linear algebra  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
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 
30 namespace Tpetra {
31 
32 #if defined(TPETRA_ENABLE_DEPRECATED_CODE)
33 [[deprecated]] Teuchos::Array<std::string> distributorSendTypes();
40 #endif
41 
104 class 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 
171  Distributor(const Distributor& distributor);
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 
623 template <class ExpView, class ImpView>
624 typename std::enable_if<(Kokkos::is_view<ExpView>::value && Kokkos::is_view<ImpView>::value)>::type
625 Distributor::
626  doPostsAndWaits(const ExpView& exports,
627  size_t numPackets,
628  const ImpView& imports) {
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
634 Distributor::
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  actor_.doPostsAndWaits(plan_, exports, numExportPacketsPerLID, imports, numImportPacketsPerLID);
640 }
641 
642 template <class ExpView, class ImpView>
643 typename std::enable_if<(Kokkos::is_view<ExpView>::value && Kokkos::is_view<ImpView>::value)>::type
644 Distributor::
645  doPosts(const ExpView& exports,
646  size_t numPackets,
647  const ImpView& imports) {
648  actor_.doPosts(plan_, exports, numPackets, imports);
649 }
650 
651 template <class ExpView, class ImpView>
652 typename std::enable_if<(Kokkos::is_view<ExpView>::value && Kokkos::is_view<ImpView>::value)>::type
653 Distributor::
654  doPosts(const ExpView& exports,
655  const Teuchos::ArrayView<const size_t>& numExportPacketsPerLID,
656  const ImpView& imports,
657  const Teuchos::ArrayView<const size_t>& numImportPacketsPerLID) {
658  actor_.doPosts(plan_, exports, numExportPacketsPerLID, imports, numImportPacketsPerLID);
659 }
660 
661 template <class ExpView, class ImpView>
662 typename std::enable_if<(Kokkos::is_view<ExpView>::value && Kokkos::is_view<ImpView>::value)>::type
663 Distributor::
664  doReversePostsAndWaits(const ExpView& exports,
665  size_t numPackets,
666  const ImpView& imports) {
667  doReversePosts(exports, numPackets, imports);
668  doReverseWaits();
669 }
670 
671 template <class ExpView, class ImpView>
672 typename std::enable_if<(Kokkos::is_view<ExpView>::value && Kokkos::is_view<ImpView>::value)>::type
673 Distributor::
674  doReversePostsAndWaits(const ExpView& exports,
675  const Teuchos::ArrayView<const size_t>& numExportPacketsPerLID,
676  const ImpView& imports,
677  const Teuchos::ArrayView<const size_t>& numImportPacketsPerLID) {
678  doReversePosts(exports, numExportPacketsPerLID, imports,
679  numImportPacketsPerLID);
680  doReverseWaits();
681 }
682 
683 template <class ExpView, class ImpView>
684 typename std::enable_if<(Kokkos::is_view<ExpView>::value && Kokkos::is_view<ImpView>::value)>::type
685 Distributor::
686  doReversePosts(const ExpView& exports,
687  size_t numPackets,
688  const ImpView& imports) {
689  // FIXME (mfh 29 Mar 2012) WHY?
690  TEUCHOS_TEST_FOR_EXCEPTION(
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 
700 template <class ExpView, class ImpView>
701 typename std::enable_if<(Kokkos::is_view<ExpView>::value && Kokkos::is_view<ImpView>::value)>::type
702 Distributor::
703  doReversePosts(const ExpView& exports,
704  const Teuchos::ArrayView<const size_t>& numExportPacketsPerLID,
705  const ImpView& imports,
706  const Teuchos::ArrayView<const size_t>& numImportPacketsPerLID) {
707  // FIXME (mfh 29 Mar 2012) WHY?
708  TEUCHOS_TEST_FOR_EXCEPTION(
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 
719 template <class OrdinalType>
720 void 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 
741  TEUCHOS_TEST_FOR_EXCEPTION(importGIDs.size() != importProcIDs.size(),
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 
802 template <class OrdinalType>
803 void 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
const Details::DistributorPlan & getPlan() const
Get this Distributor&#39;s DistributorPlan.
size_t getNumReceives() const
The number of processes from which we will receive data.
std::string description() const
Return a one-line description of this object.
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.
Teuchos::RCP< Distributor > getReverse(bool create=true) const
A reverse communication plan Distributor.
EDistributorHowInitialized
Enum indicating how and whether a Distributor was initialized.
Teuchos::RCP< const Teuchos::ParameterList > getValidParameters() const
List of valid Distributor parameters.
virtual ~Distributor()=default
Destructor (virtual for memory safety).
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.
void swap(Distributor &rhs)
Swap the contents of rhs with those of *this.
Teuchos::ArrayView< const size_t > getLengthsFrom() const
Number of values this process will receive from each process.
Teuchos::ArrayView< const int > getProcsFrom() const
Ranks of the processes sending values to this process.
size_t createFromSends(const Teuchos::ArrayView< const int > &exportProcIDs)
Set up Distributor using list of process ranks to which this process will send.
Details::EDistributorHowInitialized howInitialized() const
Return an enum indicating whether and how a Distributor was initialized.
Teuchos::ArrayView< const int > getProcsTo() const
Ranks of the processes to which this process will send values.
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...
bool hasSelfMessage() const
Whether the calling process will send or receive messages to itself.
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.
Sets up and executes a communication plan for a Tpetra DistObject.
size_t getTotalReceiveLength() const
Total number of values this process will receive from other processes.
void setParameterList(const Teuchos::RCP< Teuchos::ParameterList > &plist)
Set Distributor parameters.
Teuchos::ArrayView< const size_t > getLengthsTo() const
Number of values this process will send to each process.
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.
Stand-alone utility functions and macros.
Teuchos::Array< std::string > distributorSendTypes()
Valid string values for Distributor&#39;s &quot;Send type&quot; parameter.
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.
size_t getMaxSendLength() const
Maximum number of values this process will send to another single process.
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.
Distributor(const Teuchos::RCP< const Teuchos::Comm< int > > &comm)
Construct using the specified communicator and default parameters.
Declaration of Tpetra::Details::Behavior, a class that describes Tpetra&#39;s behavior.