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 
38  Teuchos::Array<std::string> distributorSendTypes ();
39 
102  class Distributor :
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
624  Distributor::
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
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  {
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
646  Distributor::
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
656  Distributor::
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
667  Distributor::
668  doReversePostsAndWaits (const ExpView& exports,
669  size_t numPackets,
670  const ImpView& imports)
671  {
672  doReversePosts (exports, numPackets, imports);
673  doReverseWaits ();
674  }
675 
676  template <class ExpView, class ImpView>
677  typename std::enable_if<(Kokkos::is_view<ExpView>::value && Kokkos::is_view<ImpView>::value)>::type
678  Distributor::
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);
686  doReverseWaits ();
687  }
688 
689  template <class ExpView, class ImpView>
690  typename std::enable_if<(Kokkos::is_view<ExpView>::value && Kokkos::is_view<ImpView>::value)>::type
691  Distributor::
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
709  Distributor::
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
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.
Teuchos::Array< std::string > distributorSendTypes()
Valid values for Distributor&#39;s &quot;Send type&quot; parameter.
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.
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.