Tpetra parallel linear algebra  Version of the Day
Tpetra_Details_CooMatrix.hpp
Go to the documentation of this file.
1 // @HEADER
2 // ***********************************************************************
3 //
4 // Tpetra: Templated Linear Algebra Services Package
5 // Copyright (2008) Sandia Corporation
6 //
7 // Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
8 // the U.S. Government retains certain rights in this software.
9 //
10 // Redistribution and use in source and binary forms, with or without
11 // modification, are permitted provided that the following conditions are
12 // met:
13 //
14 // 1. Redistributions of source code must retain the above copyright
15 // notice, this list of conditions and the following disclaimer.
16 //
17 // 2. Redistributions in binary form must reproduce the above copyright
18 // notice, this list of conditions and the following disclaimer in the
19 // documentation and/or other materials provided with the distribution.
20 //
21 // 3. Neither the name of the Corporation nor the names of the
22 // contributors may be used to endorse or promote products derived from
23 // this software without specific prior written permission.
24 //
25 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
26 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
29 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
30 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
31 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
32 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
33 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
34 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
35 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 //
37 // Questions? Contact Michael A. Heroux (maherou@sandia.gov)
38 //
39 // ************************************************************************
40 // @HEADER
41 
42 #ifndef TPETRA_DETAILS_COOMATRIX_HPP
43 #define TPETRA_DETAILS_COOMATRIX_HPP
44 
49 
50 #include "TpetraCore_config.h"
51 #include "Tpetra_Details_PackTriples.hpp"
52 #include "Tpetra_DistObject.hpp"
53 #include "Tpetra_Details_gathervPrint.hpp"
55 #include "Teuchos_TypeNameTraits.hpp"
56 
57 #include <initializer_list>
58 #include <map>
59 #include <memory>
60 #include <string>
61 #include <type_traits>
62 #include <vector>
63 
64 
65 namespace Tpetra {
66 namespace Details {
67 
68 // Implementation details of Tpetra::Details.
69 // So, users REALLY should not use anything in here.
70 namespace Impl {
71 
74 template<class IndexType>
75 struct CooGraphEntry {
76  IndexType row;
77  IndexType col;
78 };
79 
84 template<class IndexType>
86  bool
87  operator () (const CooGraphEntry<IndexType>& x,
88  const CooGraphEntry<IndexType>& y) const
89  {
90  return (x.row < y.row) || (x.row == y.row && x.col < y.col);
91  }
92 };
93 
96 template<class SC, class GO>
98 private:
106  typedef std::map<CooGraphEntry<GO>, SC,
107  CompareCooGraphEntries<GO> > entries_type;
108 
111  entries_type entries_;
112 
113 public:
115  typedef char packet_type;
116 
118  CooMatrixImpl () = default;
119 
126  void
127  sumIntoGlobalValue (const GO gblRowInd,
128  const GO gblColInd,
129  const SC& val)
130  {
131  // There's no sense in worrying about the insertion hint, since
132  // indices may be all over the place. Users make no promises of
133  // sorting or locality of input.
134  CooGraphEntry<GO> ij {gblRowInd, gblColInd};
135  auto result = this->entries_.insert ({ij, val});
136  if (! result.second) { // already in the map
137  result.first->second += val; // sum in the new value
138  }
139  }
140 
149  void
150  sumIntoGlobalValues (const GO gblRowInds[],
151  const GO gblColInds[],
152  const SC vals[],
153  const std::size_t numEnt)
154  {
155  for (std::size_t k = 0; k < numEnt; ++k) {
156  // There's no sense in worrying about the insertion hint, since
157  // indices may be all over the place. Users make no promises of
158  // sorting or locality of input.
159  CooGraphEntry<GO> ij {gblRowInds[k], gblColInds[k]};
160  const SC val = vals[k];
161  auto result = this->entries_.insert ({ij, val});
162  if (! result.second) { // already in the map
163  result.first->second += val; // sum in the new value
164  }
165  }
166  }
167 
169  std::size_t
171  {
172  return this->entries_.size ();
173  }
174 
178  void
179  forAllEntries (std::function<void (const GO, const GO, const SC&)> f) const
180  {
181  for (auto iter = this->entries_.begin ();
182  iter != this->entries_.end (); ++iter) {
183  f (iter->first.row, iter->first.col, iter->second);
184  }
185  }
186 
192  void
193  mergeIntoRow (const GO tgtGblRow,
194  const CooMatrixImpl<SC, GO>& src,
195  const GO srcGblRow)
196  {
197  // const char prefix[] =
198  // "Tpetra::Details::Impl::CooMatrixImpl::mergeIntoRow: ";
199 
200  entries_type& tgtEntries = this->entries_;
201  const entries_type& srcEntries = src.entries_;
202 
203  // Find all entries with the given global row index. The min GO
204  // value is guaranteed to be the least possible column index, so
205  // beg1 is a lower bound for all (row index, column index) pairs.
206  // Lower bound is inclusive; upper bound is exclusive.
207  auto srcBeg = srcEntries.lower_bound ({srcGblRow, std::numeric_limits<GO>::min ()});
208  auto srcEnd = srcEntries.upper_bound ({srcGblRow+1, std::numeric_limits<GO>::min ()});
209  auto tgtBeg = tgtEntries.lower_bound ({tgtGblRow, std::numeric_limits<GO>::min ()});
210  auto tgtEnd = tgtEntries.upper_bound ({tgtGblRow+1, std::numeric_limits<GO>::min ()});
211 
212  // Don't waste time iterating over the current row of *this, if
213  // the current row of src is empty.
214  if (srcBeg != srcEnd) {
215  for (auto tgtCur = tgtBeg; tgtCur != tgtEnd; ++tgtCur) {
216  auto srcCur = srcBeg;
217  while (srcCur != srcEnd && srcCur->first.col < tgtCur->first.col) {
218  ++srcCur;
219  }
220  // At this point, one of the following is true:
221  //
222  // 1. srcCur == srcEnd, thus nothing more to insert.
223  // 2. srcCur->first.col > tgtCur->first.col, thus the current
224  // row of src has no entry matching tgtCur->first, so we
225  // have to insert it. Insertion does not invalidate
226  // tgtEntries iterators, and neither srcEntries nor
227  // tgtEntries have duplicates, so this is safe.
228  // 3. srcCur->first.col == tgtCur->first.col, so add the two entries.
229  if (srcCur != srcEnd) {
230  if (srcCur->first.col == tgtCur->first.col) {
231  tgtCur->second += srcCur->second;
232  }
233  else {
234  // tgtCur is (optimally) right before where we want to put
235  // the new entry, since srcCur points to the first entry
236  // in srcEntries whose column index is greater than that
237  // of the entry to which tgtCur points.
238  (void) tgtEntries.insert (tgtCur, *srcCur);
239  }
240  } // if srcCur != srcEnd
241  } // for each entry in the current row (lclRow) of *this
242  } // if srcBeg != srcEnd
243  }
244 
254  int
255  countPackRow (int& numPackets,
256  const GO gblRow,
257  const ::Teuchos::Comm<int>& comm,
258  std::ostream* errStrm = NULL) const
259  {
260  using ::Tpetra::Details::countPackTriples;
261  using ::Tpetra::Details::countPackTriplesCount;
262  using std::endl;
263  const char prefix[] = "Tpetra::Details::Impl::CooMatrixImpl::countPackRow: ";
264 #ifdef HAVE_TPETRACORE_MPI
265  int errCode = MPI_SUCCESS;
266 #else
267  int errCode = 0;
268 #endif // HAVE_TPETRACORE_MPI
269 
270  // Count the number of entries in the given row.
271  const GO minGO = std::numeric_limits<GO>::min ();
272  auto beg = this->entries_.lower_bound ({gblRow, minGO});
273  auto end = this->entries_.upper_bound ({gblRow+1, minGO});
274  int numEnt = 0;
275  for (auto iter = beg; iter != end; ++iter) {
276  ++numEnt;
277  if (numEnt == std::numeric_limits<int>::max ()) {
278  if (errStrm != NULL) {
279  *errStrm << prefix << "In (global) row " << gblRow << ", the number "
280  "of entries thus far, numEnt = " << numEnt << ", has reached the "
281  "maximum int value. We need to store this count as int for MPI's "
282  "sake." << endl;
283  }
284  return -1;
285  }
286  }
287 
288  int numPacketsForCount = 0; // output argument of countPackTriplesCount
289  {
290  errCode =
291  countPackTriplesCount (comm, numPacketsForCount, errStrm);
292  if (errCode != 0) {
293  if (errStrm != NULL) {
294  *errStrm << prefix << "countPackTriplesCount "
295  "returned errCode = " << errCode << " != 0." << endl;
296  }
297  return errCode;
298  }
299  if (numPacketsForCount < 0) {
300  if (errStrm != NULL) {
301  *errStrm << prefix << "countPackTriplesCount returned "
302  "numPacketsForCount = " << numPacketsForCount << " < 0." << endl;
303  }
304  return -1;
305  }
306  }
307 
308  int numPacketsForTriples = 0; // output argument of countPackTriples
309  {
310  errCode = countPackTriples<SC, GO> (numEnt, comm, numPacketsForTriples);
311  TEUCHOS_TEST_FOR_EXCEPTION
312  (errCode != 0, std::runtime_error, prefix << "countPackTriples "
313  "returned errCode = " << errCode << " != 0.");
314  TEUCHOS_TEST_FOR_EXCEPTION
315  (numPacketsForTriples < 0, std::logic_error, prefix << "countPackTriples "
316  "returned numPacketsForTriples = " << numPacketsForTriples << " < 0.");
317  }
318 
319  numPackets = numPacketsForCount + numPacketsForTriples;
320  return errCode;
321  }
322 
337  void
338  packRow (packet_type outBuf[],
339  const int outBufSize,
340  int& outBufCurPos, // in/out argument
341  const ::Teuchos::Comm<int>& comm,
342  std::vector<GO>& gblRowInds,
343  std::vector<GO>& gblColInds,
344  std::vector<SC>& vals,
345  const GO gblRow) const
346  {
347  using ::Tpetra::Details::packTriples;
348  using ::Tpetra::Details::packTriplesCount;
349  const char prefix[] = "Tpetra::Details::Impl::CooMatrixImpl::packRow: ";
350 
351  const GO minGO = std::numeric_limits<GO>::min ();
352  auto beg = this->entries_.lower_bound ({gblRow, minGO});
353  auto end = this->entries_.upper_bound ({gblRow+1, minGO});
354 
355  // This doesn't actually deallocate. Only swapping with an empty
356  // std::vector does that.
357  gblRowInds.resize (0);
358  gblColInds.resize (0);
359  vals.resize (0);
360 
361  int numEnt = 0;
362  for (auto iter = beg; iter != end; ++iter) {
363  gblRowInds.push_back (iter->first.row);
364  gblColInds.push_back (iter->first.col);
365  vals.push_back (iter->second);
366  ++numEnt;
367  TEUCHOS_TEST_FOR_EXCEPTION
368  (numEnt == std::numeric_limits<int>::max (), std::runtime_error, prefix
369  << "In (global) row " << gblRow << ", the number of entries thus far, "
370  "numEnt = " << numEnt << ", has reached the maximum int value. "
371  "We need to store this count as int for MPI's sake.");
372  }
373 
374  {
375  const int errCode =
376  packTriplesCount (numEnt, outBuf, outBufSize, outBufCurPos, comm);
377  TEUCHOS_TEST_FOR_EXCEPTION
378  (errCode != 0, std::runtime_error, prefix
379  << "In (global) row " << gblRow << ", packTriplesCount returned "
380  "errCode = " << errCode << " != 0.");
381  }
382  {
383  const int errCode =
384  packTriples (gblRowInds.data (),
385  gblColInds.data (),
386  vals.data (),
387  numEnt,
388  outBuf,
389  outBufSize,
390  outBufCurPos, // in/out argument
391  comm);
392  TEUCHOS_TEST_FOR_EXCEPTION
393  (errCode != 0, std::runtime_error, prefix << "In (global) row "
394  << gblRow << ", packTriples returned errCode = " << errCode
395  << " != 0.");
396  }
397  }
398 
406  GO
407  getMyGlobalRowIndices (std::vector<GO>& rowInds) const
408  {
409  rowInds.clear ();
410 
411  GO lclMinRowInd = std::numeric_limits<GO>::max (); // compute local min
412  for (typename entries_type::const_iterator iter = this->entries_.begin ();
413  iter != this->entries_.end (); ++iter) {
414  const GO rowInd = iter->first.row;
415  if (rowInd < lclMinRowInd) {
416  lclMinRowInd = rowInd;
417  }
418  if (rowInds.empty () || rowInds.back () != rowInd) {
419  rowInds.push_back (rowInd); // don't insert duplicates
420  }
421  }
422  return lclMinRowInd;
423  }
424 
425  template<class OffsetType>
426  void
427  buildCrs (std::vector<OffsetType>& rowOffsets,
428  GO gblColInds[],
429  SC vals[]) const
430  {
431  static_assert (std::is_integral<OffsetType>::value,
432  "OffsetType must be a built-in integer type.");
433 
434  // clear() doesn't generally free storage; it just resets the
435  // length. Thus, we reuse any existing storage here.
436  rowOffsets.clear ();
437 
438  const std::size_t numEnt = this->getLclNumEntries ();
439  if (numEnt == 0) {
440  rowOffsets.push_back (0);
441  }
442  else {
443  typename entries_type::const_iterator iter = this->entries_.begin ();
444  GO prevGblRowInd = iter->first.row;
445 
446  OffsetType k = 0;
447  for ( ; iter != this->entries_.end (); ++iter, ++k) {
448  const GO gblRowInd = iter->first.row;
449  if (k == 0 || gblRowInd != prevGblRowInd) {
450  // The row offsets array always has at least one entry. The
451  // first entry is always zero, and the last entry is always
452  // the number of matrix entries.
453  rowOffsets.push_back (k);
454  prevGblRowInd = gblRowInd;
455  }
456  gblColInds[k] = iter->first.col;
457 
458  static_assert (std::is_same<typename std::decay<decltype (iter->second)>::type, SC>::value,
459  "The type of iter->second != SC.");
460  vals[k] = iter->second;
461  }
462  rowOffsets.push_back (static_cast<OffsetType> (numEnt));
463  }
464  }
465 
478  template<class OffsetType, class LO>
479  void
480  buildLocallyIndexedCrs (std::vector<OffsetType>& rowOffsets,
481  LO lclColInds[],
482  SC vals[],
483  std::function<LO (const GO)> gblToLcl) const
484  {
485  static_assert (std::is_integral<OffsetType>::value,
486  "OffsetType must be a built-in integer type.");
487  static_assert (std::is_integral<LO>::value,
488  "LO must be a built-in integer type.");
489 
490  // clear() doesn't generally free storage; it just resets the
491  // length. Thus, we reuse any existing storage here.
492  rowOffsets.clear ();
493 
494  const std::size_t numEnt = this->getLclNumEntries ();
495  if (numEnt == 0) {
496  rowOffsets.push_back (0);
497  }
498  else {
499  typename entries_type::const_iterator iter = this->entries_.begin ();
500  GO prevGblRowInd = iter->first.row;
501 
502  OffsetType k = 0;
503  for ( ; iter != this->entries_.end (); ++iter, ++k) {
504  const GO gblRowInd = iter->first.row;
505  if (k == 0 || gblRowInd != prevGblRowInd) {
506  // The row offsets array always has at least one entry. The
507  // first entry is always zero, and the last entry is always
508  // the number of matrix entries.
509  rowOffsets.push_back (k);
510  prevGblRowInd = gblRowInd;
511  }
512  lclColInds[k] = gblToLcl (iter->first.col);
513  vals[k] = iter->second;
514  }
515  rowOffsets.push_back (static_cast<OffsetType> (numEnt));
516  }
517  }
518 };
519 
520 } // namespace Impl
521 
570 template<class SC,
574 class CooMatrix : public ::Tpetra::DistObject<char, LO, GO, NT> {
575 public:
577  typedef char packet_type;
579  typedef SC scalar_type;
580  typedef LO local_ordinal_type;
581  typedef GO global_ordinal_type;
582  typedef NT node_type;
583  typedef typename NT::device_type device_type;
585  typedef ::Tpetra::Map<local_ordinal_type, global_ordinal_type, node_type> map_type;
586 
587 private:
589  typedef ::Tpetra::DistObject<packet_type, local_ordinal_type,
590  global_ordinal_type, node_type> base_type;
591 
594 
595 public:
602  base_type (::Teuchos::null),
603  localError_ (new bool (false)),
604  errs_ (new std::shared_ptr<std::ostringstream> ()) // ptr to a null ptr
605  {}
606 
614  CooMatrix (const ::Teuchos::RCP<const map_type>& map) :
615  base_type (map),
616  localError_ (new bool (false)),
617  errs_ (new std::shared_ptr<std::ostringstream> ()) // ptr to a null ptr
618  {}
619 
621  virtual ~CooMatrix () {}
622 
629  void
630  sumIntoGlobalValue (const GO gblRowInd,
631  const GO gblColInd,
632  const SC& val)
633  {
634  this->impl_.sumIntoGlobalValue (gblRowInd, gblColInd, val);
635  }
636 
645  void
646  sumIntoGlobalValues (const GO gblRowInds[],
647  const GO gblColInds[],
648  const SC vals[],
649  const std::size_t numEnt)
650  {
651  this->impl_.sumIntoGlobalValues (gblRowInds, gblColInds, vals, numEnt);
652  }
653 
655  void
656  sumIntoGlobalValues (std::initializer_list<GO> gblRowInds,
657  std::initializer_list<GO> gblColInds,
658  std::initializer_list<SC> vals,
659  const std::size_t numEnt)
660  {
661  this->impl_.sumIntoGlobalValues (gblRowInds.begin (), gblColInds.begin (),
662  vals.begin (), numEnt);
663  }
664 
666  std::size_t
668  {
669  return this->impl_.getLclNumEntries ();
670  }
671 
672  template<class OffsetType>
673  void
674  buildCrs (::Kokkos::View<OffsetType*, device_type>& rowOffsets,
675  ::Kokkos::View<GO*, device_type>& gblColInds,
676  ::Kokkos::View<typename ::Kokkos::Details::ArithTraits<SC>::val_type*, device_type>& vals)
677  {
678  static_assert (std::is_integral<OffsetType>::value,
679  "OffsetType must be a built-in integer type.");
680  using ::Kokkos::create_mirror_view;
682  using ::Kokkos::View;
683  typedef typename ::Kokkos::Details::ArithTraits<SC>::val_type ISC;
684 
685  const std::size_t numEnt = this->getLclNumEntries ();
686 
687  gblColInds = View<GO*, device_type> ("gblColInds", numEnt);
688  vals = View<ISC*, device_type> ("vals", numEnt);
689  auto gblColInds_h = create_mirror_view (gblColInds);
690  auto vals_h = create_mirror_view (vals);
691 
692  std::vector<std::size_t> rowOffsetsSV;
693  this->impl_.buildCrs (rowOffsetsSV,
694  gblColInds_h.data (),
695  vals_h.data ());
696  rowOffsets =
697  View<OffsetType*, device_type> ("rowOffsets", rowOffsetsSV.size ());
698  typename View<OffsetType*, device_type>::HostMirror
699  rowOffsets_h (rowOffsetsSV.data (), rowOffsetsSV.size ());
700  deep_copy (rowOffsets, rowOffsets_h);
701 
702  deep_copy (gblColInds, gblColInds_h);
703  deep_copy (vals, vals_h);
704  }
705 
716  void
717  fillComplete (const ::Teuchos::RCP<const ::Teuchos::Comm<int> >& comm)
718  {
719  if (comm.is_null ()) {
720  this->map_ = ::Teuchos::null;
721  }
722  else {
723  this->map_ = this->buildMap (comm);
724  }
725  }
726 
735  void
737  {
738  TEUCHOS_TEST_FOR_EXCEPTION
739  (this->getMap ().is_null (), std::runtime_error, "Tpetra::Details::"
740  "CooMatrix::fillComplete: This object does not yet have a Map. "
741  "You must call the version of fillComplete "
742  "that takes an input communicator.");
743  this->fillComplete (this->getMap ()->getComm ());
744  }
745 
760  bool localError () const {
761  return *localError_;
762  }
763 
781  std::string errorMessages () const {
782  return ((*errs_).get () == NULL) ? std::string ("") : (*errs_)->str ();
783  }
784 
785 private:
798  std::shared_ptr<bool> localError_;
799 
807  std::shared_ptr<std::shared_ptr<std::ostringstream> > errs_;
808 
810  std::ostream&
811  markLocalErrorAndGetStream ()
812  {
813  * (this->localError_) = true;
814  if ((*errs_).get () == NULL) {
815  *errs_ = std::shared_ptr<std::ostringstream> (new std::ostringstream ());
816  }
817  return **errs_;
818  }
819 
820 public:
823  virtual std::string description () const {
824  using Teuchos::TypeNameTraits;
825 
826  std::ostringstream os;
827  os << "\"Tpetra::Details::CooMatrix\": {"
828  << "SC: " << TypeNameTraits<SC>::name ()
829  << ", LO: " << TypeNameTraits<LO>::name ()
830  << ", GO: " << TypeNameTraits<GO>::name ()
831  << ", NT: " << TypeNameTraits<NT>::name ();
832  if (this->getObjectLabel () != "") {
833  os << ", Label: \"" << this->getObjectLabel () << "\"";
834  }
835  os << ", Has Map: " << (this->map_.is_null () ? "false" : "true")
836  << "}";
837  return os.str ();
838  }
839 
842  virtual void
843  describe (Teuchos::FancyOStream& out,
844  const Teuchos::EVerbosityLevel verbLevel =
845  Teuchos::Describable::verbLevel_default) const
846  {
847  using ::Tpetra::Details::gathervPrint;
848  using ::Teuchos::EVerbosityLevel;
849  using ::Teuchos::OSTab;
850  using ::Teuchos::TypeNameTraits;
851  using ::Teuchos::VERB_DEFAULT;
852  using ::Teuchos::VERB_LOW;
853  using ::Teuchos::VERB_MEDIUM;
854  using std::endl;
855 
856  const auto vl = (verbLevel == VERB_DEFAULT) ? VERB_LOW : verbLevel;
857 
858  auto comm = this->getMap ().is_null () ?
859  Teuchos::null : this->getMap ()->getComm ();
860  const int myRank = comm.is_null () ? 0 : comm->getRank ();
861  // const int numProcs = comm.is_null () ? 1 : comm->getSize ();
862 
863  if (vl != Teuchos::VERB_NONE) {
864  // Convention is to start describe() implementations with a tab.
865  OSTab tab0 (out);
866  if (myRank == 0) {
867  out << "\"Tpetra::Details::CooMatrix\":" << endl;
868  }
869  OSTab tab1 (out);
870  if (myRank == 0) {
871  out << "Template parameters:" << endl;
872  {
873  OSTab tab2 (out);
874  out << "SC: " << TypeNameTraits<SC>::name () << endl
875  << "LO: " << TypeNameTraits<LO>::name () << endl
876  << "GO: " << TypeNameTraits<GO>::name () << endl
877  << "NT: " << TypeNameTraits<NT>::name () << endl;
878  }
879  if (this->getObjectLabel () != "") {
880  out << "Label: \"" << this->getObjectLabel () << "\"" << endl;
881  }
882  out << "Has Map: " << (this->map_.is_null () ? "false" : "true") << endl;
883  } // if myRank == 0
884 
885  // Describe the Map, if it exists.
886  if (! this->map_.is_null ()) {
887  if (myRank == 0) {
888  out << "Map:" << endl;
889  }
890  OSTab tab2 (out);
891  this->map_->describe (out, vl);
892  }
893 
894  // At verbosity > VERB_LOW, each process prints something.
895  if (vl > VERB_LOW) {
896  std::ostringstream os;
897  os << "Process " << myRank << ":" << endl;
898  //OSTab tab3 (os);
899 
900  const std::size_t numEnt = this->impl_.getLclNumEntries ();
901  os << " Local number of entries: " << numEnt << endl;
902  if (vl > VERB_MEDIUM) {
903  os << " Local entries:" << endl;
904  //OSTab tab4 (os);
905  this->impl_.forAllEntries ([&os] (const GO row, const GO col, const SC& val) {
906  os << " {"
907  << "row: " << row
908  << ", col: " << col
909  << ", val: " << val
910  << "}" << endl;
911  });
912  }
913  gathervPrint (out, os.str (), *comm);
914  }
915  } // vl != Teuchos::VERB_NONE
916  }
917 
918 private:
927  Teuchos::RCP<const map_type>
928  buildMap (const ::Teuchos::RCP<const ::Teuchos::Comm<int> >& comm)
929  {
930  using ::Teuchos::outArg;
931  using ::Teuchos::rcp;
932  using ::Teuchos::REDUCE_MIN;
933  using ::Teuchos::reduceAll;
934  typedef ::Tpetra::global_size_t GST;
935  //const char prefix[] = "Tpetra::Details::CooMatrix::buildMap: ";
936 
937  // Processes where comm is null don't participate in the Map.
938  if (comm.is_null ()) {
939  return ::Teuchos::null;
940  }
941 
942  // mfh 17 Jan 2017: We just happen to use row indices, because
943  // that's what Tpetra::CrsMatrix currently uses. That's probably
944  // not the best thing to use, but it's not bad for commonly
945  // encountered matrices. A better more general approach might be
946  // to hash (row index, column index) pairs to a global index. One
947  // could make that unique by doing a parallel scan at map
948  // construction time.
949 
950  std::vector<GO> rowInds;
951  const GO lclMinGblRowInd = this->impl_.getMyGlobalRowIndices (rowInds);
952 
953  // Compute the globally min row index for the "index base."
954  GO gblMinGblRowInd = 0; // output argument
955  reduceAll<int, GO> (*comm, REDUCE_MIN, lclMinGblRowInd,
956  outArg (gblMinGblRowInd));
957  const GO indexBase = gblMinGblRowInd;
958  const GST INV = Tpetra::Details::OrdinalTraits<GST>::invalid ();
959  return rcp (new map_type (INV, rowInds.data (), rowInds.size (),
960  indexBase, comm));
961  }
962 
963 protected:
967  virtual size_t constantNumberOfPackets () const {
968  return static_cast<size_t> (0);
969  }
970 
974  virtual bool
975  checkSizes (const ::Tpetra::SrcDistObject& source)
976  {
977  using std::endl;
979  const char prefix[] = "Tpetra::Details::CooMatrix::checkSizes: ";
980 
981  const this_type* src = dynamic_cast<const this_type* > (&source);
982 
983  if (src == NULL) {
984  std::ostream& err = markLocalErrorAndGetStream ();
985  err << prefix << "The source object of the Import or Export "
986  "must be a CooMatrix with the same template parameters as the "
987  "target object." << endl;
988  }
989  else if (this->map_.is_null ()) {
990  std::ostream& err = markLocalErrorAndGetStream ();
991  err << prefix << "The target object of the Import or Export "
992  "must be a CooMatrix with a nonnull Map." << endl;
993  }
994  return ! (* (this->localError_));
995  }
996 
999  typename ::Tpetra::DistObject<char, LO, GO, NT>::buffer_device_type;
1000 
1001  virtual void
1002 #ifdef TPETRA_ENABLE_DEPRECATED_CODE
1003  copyAndPermuteNew
1004 #else // TPETRA_ENABLE_DEPRECATED_CODE
1005  copyAndPermute
1006 #endif // TPETRA_ENABLE_DEPRECATED_CODE
1007  (const ::Tpetra::SrcDistObject& sourceObject,
1008  const size_t numSameIDs,
1009  const Kokkos::DualView<const LO*,
1010  buffer_device_type>& permuteToLIDs,
1011  const Kokkos::DualView<const LO*,
1012  buffer_device_type>& permuteFromLIDs)
1013  {
1014  using std::endl;
1016  const char prefix[] = "Tpetra::Details::CooMatrix::copyAndPermute: ";
1017 
1018  // There's no communication in this method, so it's safe just to
1019  // return on error.
1020 
1021  if (* (this->localError_)) {
1022  std::ostream& err = this->markLocalErrorAndGetStream ();
1023  err << prefix << "The target object of the Import or Export is "
1024  "already in an error state." << endl;
1025  return;
1026  }
1027 
1028  const this_type* src = dynamic_cast<const this_type*> (&sourceObject);
1029  if (src == nullptr) {
1030  std::ostream& err = this->markLocalErrorAndGetStream ();
1031  err << prefix << "Input argument 'sourceObject' is not a CooMatrix."
1032  << endl;
1033  return;
1034  }
1035 
1036  const size_t numPermuteIDs =
1037  static_cast<size_t> (permuteToLIDs.extent (0));
1038  if (numPermuteIDs != static_cast<size_t> (permuteFromLIDs.extent (0))) {
1039  std::ostream& err = this->markLocalErrorAndGetStream ();
1040  err << prefix << "permuteToLIDs.extent(0) = "
1041  << numPermuteIDs << " != permuteFromLIDs.extent(0) = "
1042  << permuteFromLIDs.extent (0) << "." << endl;
1043  return;
1044  }
1045  if (sizeof (int) <= sizeof (size_t) &&
1046  numPermuteIDs > static_cast<size_t> (std::numeric_limits<int>::max ())) {
1047  std::ostream& err = this->markLocalErrorAndGetStream ();
1048  err << prefix << "numPermuteIDs = " << numPermuteIDs
1049  << ", a size_t, overflows int." << endl;
1050  return;
1051  }
1052 
1053  // Even though this is an std::set, we can start with numSameIDs
1054  // just by iterating through the first entries of the set.
1055 
1056  if (sizeof (int) <= sizeof (size_t) &&
1057  numSameIDs > static_cast<size_t> (std::numeric_limits<int>::max ())) {
1058  std::ostream& err = this->markLocalErrorAndGetStream ();
1059  err << prefix << "numSameIDs = " << numSameIDs
1060  << ", a size_t, overflows int." << endl;
1061  return;
1062  }
1063 
1064  //
1065  // Copy in entries from any initial rows with the same global row indices.
1066  //
1067  const LO numSame = static_cast<int> (numSameIDs);
1068  // Count of local row indices encountered here with invalid global
1069  // row indices. If nonzero, something went wrong. If something
1070  // did go wrong, we'll defer responding until the end of this
1071  // method, so we can print as much useful info as possible.
1072  LO numInvalidSameRows = 0;
1073  for (LO lclRow = 0; lclRow < numSame; ++lclRow) {
1074  // All numSame initial rows have the same global index in both
1075  // source and target Maps, so we only need to convert to global
1076  // once.
1077  const GO gblRow = this->map_->getGlobalElement (lclRow);
1078  if (gblRow == ::Tpetra::Details::OrdinalTraits<GO>::invalid ()) {
1079  ++numInvalidSameRows;
1080  continue;
1081  }
1082  else {
1083  this->impl_.mergeIntoRow (gblRow, src->impl_, gblRow);
1084  }
1085  }
1086 
1087  //
1088  // Copy in entries from remaining rows that are permutations, that
1089  // is, that live in both the source and target Maps, but aren't
1090  // included in the "same" list (see above).
1091  //
1092  const LO numPermute = static_cast<int> (numPermuteIDs);
1093  // Count of local "from" row indices encountered here with invalid
1094  // global row indices. If nonzero, something went wrong. If
1095  // something did go wrong, we'll defer responding until the end of
1096  // this method, so we can print as much useful info as possible.
1097  LO numInvalidRowsFrom = 0;
1098  // Count of local "to" row indices encountered here with invalid
1099  // global row indices. If nonzero, something went wrong. If
1100  // something did go wrong, we'll defer responding until the end of
1101  // this method, so we can print as much useful info as possible.
1102  LO numInvalidRowsTo = 0;
1103 
1104  TEUCHOS_ASSERT( ! permuteFromLIDs.need_sync_host () );
1105  TEUCHOS_ASSERT( ! permuteToLIDs.need_sync_host () );
1106  auto permuteFromLIDs_h = permuteFromLIDs.view_host ();
1107  auto permuteToLIDs_h = permuteToLIDs.view_host ();
1108 
1109  for (LO k = 0; k < numPermute; ++k) {
1110  const LO lclRowFrom = permuteFromLIDs_h[k];
1111  const LO lclRowTo = permuteToLIDs_h[k];
1112  const GO gblRowFrom = src->map_->getGlobalElement (lclRowFrom);
1113  const GO gblRowTo = this->map_->getGlobalElement (lclRowTo);
1114 
1115  bool bothConversionsValid = true;
1116  if (gblRowFrom == ::Tpetra::Details::OrdinalTraits<GO>::invalid ()) {
1117  ++numInvalidRowsFrom;
1118  bothConversionsValid = false;
1119  }
1120  if (gblRowTo == ::Tpetra::Details::OrdinalTraits<GO>::invalid ()) {
1121  ++numInvalidRowsTo;
1122  bothConversionsValid = false;
1123  }
1124  if (bothConversionsValid) {
1125  this->impl_.mergeIntoRow (gblRowTo, src->impl_, gblRowFrom);
1126  }
1127  }
1128 
1129  // Print info if any errors occurred.
1130  if (numInvalidSameRows != 0 || numInvalidRowsFrom != 0 ||
1131  numInvalidRowsTo != 0) {
1132  // Collect and print all the invalid input row indices, for the
1133  // "same," "from," and "to" lists.
1134  std::vector<std::pair<LO, GO> > invalidSameRows;
1135  invalidSameRows.reserve (numInvalidSameRows);
1136  std::vector<std::pair<LO, GO> > invalidRowsFrom;
1137  invalidRowsFrom.reserve (numInvalidRowsFrom);
1138  std::vector<std::pair<LO, GO> > invalidRowsTo;
1139  invalidRowsTo.reserve (numInvalidRowsTo);
1140 
1141  for (LO lclRow = 0; lclRow < numSame; ++lclRow) {
1142  // All numSame initial rows have the same global index in both
1143  // source and target Maps, so we only need to convert to global
1144  // once.
1145  const GO gblRow = this->map_->getGlobalElement (lclRow);
1146  if (gblRow == ::Tpetra::Details::OrdinalTraits<GO>::invalid ()) {
1147  invalidSameRows.push_back ({lclRow, gblRow});
1148  }
1149  }
1150 
1151  for (LO k = 0; k < numPermute; ++k) {
1152  const LO lclRowFrom = permuteFromLIDs_h[k];
1153  const LO lclRowTo = permuteToLIDs_h[k];
1154  const GO gblRowFrom = src->map_->getGlobalElement (lclRowFrom);
1155  const GO gblRowTo = this->map_->getGlobalElement (lclRowTo);
1156 
1157  if (gblRowFrom == ::Tpetra::Details::OrdinalTraits<GO>::invalid ()) {
1158  invalidRowsFrom.push_back ({lclRowFrom, gblRowFrom});
1159  }
1160  if (gblRowTo == ::Tpetra::Details::OrdinalTraits<GO>::invalid ()) {
1161  invalidRowsTo.push_back ({lclRowTo, gblRowTo});
1162  }
1163  }
1164 
1165  std::ostringstream os;
1166  if (numInvalidSameRows != 0) {
1167  os << "Invalid permute \"same\" (local, global) index pairs: [";
1168  for (std::size_t k = 0; k < invalidSameRows.size (); ++k) {
1169  const auto& p = invalidSameRows[k];
1170  os << "(" << p.first << "," << p.second << ")";
1171  if (k + 1 < invalidSameRows.size ()) {
1172  os << ", ";
1173  }
1174  }
1175  os << "]" << std::endl;
1176  }
1177  if (numInvalidRowsFrom != 0) {
1178  os << "Invalid permute \"from\" (local, global) index pairs: [";
1179  for (std::size_t k = 0; k < invalidRowsFrom.size (); ++k) {
1180  const auto& p = invalidRowsFrom[k];
1181  os << "(" << p.first << "," << p.second << ")";
1182  if (k + 1 < invalidRowsFrom.size ()) {
1183  os << ", ";
1184  }
1185  }
1186  os << "]" << std::endl;
1187  }
1188  if (numInvalidRowsTo != 0) {
1189  os << "Invalid permute \"to\" (local, global) index pairs: [";
1190  for (std::size_t k = 0; k < invalidRowsTo.size (); ++k) {
1191  const auto& p = invalidRowsTo[k];
1192  os << "(" << p.first << "," << p.second << ")";
1193  if (k + 1 < invalidRowsTo.size ()) {
1194  os << ", ";
1195  }
1196  }
1197  os << "]" << std::endl;
1198  }
1199 
1200  std::ostream& err = this->markLocalErrorAndGetStream ();
1201  err << prefix << os.str ();
1202  return;
1203  }
1204  }
1205 
1206  virtual void
1207 #ifdef TPETRA_ENABLE_DEPRECATED_CODE
1208  packAndPrepareNew
1209 #else // TPETRA_ENABLE_DEPRECATED_CODE
1210  packAndPrepare
1211 #endif // TPETRA_ENABLE_DEPRECATED_CODE
1212  (const ::Tpetra::SrcDistObject& sourceObject,
1213  const Kokkos::DualView<const local_ordinal_type*,
1214  buffer_device_type>& exportLIDs,
1215  Kokkos::DualView<packet_type*,
1216  buffer_device_type>& exports,
1217  Kokkos::DualView<size_t*,
1218  buffer_device_type> numPacketsPerLID,
1219  size_t& constantNumPackets,
1220  ::Tpetra::Distributor& /* distor */)
1221  {
1222  using Teuchos::Comm;
1223  using Teuchos::RCP;
1224  using std::endl;
1225  using this_type = CooMatrix<SC, LO, GO, NT>;
1226  const char prefix[] = "Tpetra::Details::CooMatrix::packAndPrepare: ";
1227  const char suffix[] = " This should never happen. "
1228  "Please report this bug to the Tpetra developers.";
1229 
1230  // Tell the caller that different rows may have different numbers
1231  // of matrix entries.
1232  constantNumPackets = 0;
1233 
1234  const this_type* src = dynamic_cast<const this_type*> (&sourceObject);
1235  if (src == nullptr) {
1236  std::ostream& err = this->markLocalErrorAndGetStream ();
1237  err << prefix << "Input argument 'sourceObject' is not a CooMatrix."
1238  << endl;
1239  }
1240  else if (* (src->localError_)) {
1241  std::ostream& err = this->markLocalErrorAndGetStream ();
1242  err << prefix << "The source (input) object of the Import or Export "
1243  "is already in an error state on this process."
1244  << endl;
1245  }
1246  else if (* (this->localError_)) {
1247  std::ostream& err = this->markLocalErrorAndGetStream ();
1248  err << prefix << "The target (output, \"this\") object of the Import "
1249  "or Export is already in an error state on this process." << endl;
1250  }
1251  // Respond to detected error(s) by resizing 'exports' to zero (so
1252  // we won't be tempted to read it later), and filling
1253  // numPacketsPerLID with zeros.
1254  if (* (this->localError_)) {
1255  // Resize 'exports' to zero, so we won't be tempted to read it.
1256  Details::reallocDualViewIfNeeded (exports, 0, "CooMatrix exports");
1257  // Trick to get around const DualView& being const.
1258  {
1259  auto numPacketsPerLID_tmp = numPacketsPerLID;
1260  numPacketsPerLID_tmp.sync_host ();
1261  numPacketsPerLID_tmp.modify_host ();
1262  }
1263  // Fill numPacketsPerLID with zeros.
1264  Kokkos::deep_copy (numPacketsPerLID.h_view, static_cast<size_t> (0));
1265  return;
1266  }
1267 
1268  const size_t numExports = exportLIDs.extent (0);
1269  if (numExports == 0) {
1270  Details::reallocDualViewIfNeeded (exports, 0, exports.h_view.label ());
1271  return; // nothing to send
1272  }
1273  RCP<const Comm<int> > comm = src->getMap ().is_null () ?
1274  Teuchos::null : src->getMap ()->getComm ();
1275  if (comm.is_null () || comm->getSize () == 1) {
1276  if (numExports != static_cast<size_t> (0)) {
1277  std::ostream& err = this->markLocalErrorAndGetStream ();
1278  err << prefix << "The input communicator is either null or "
1279  "has only one process, but numExports = " << numExports << " != 0."
1280  << suffix << endl;
1281  return;
1282  }
1283  // Don't go into the rest of this method unless there are
1284  // actually processes other than the calling process. This is
1285  // because the pack and unpack functions only have nonstub
1286  // implementations if building with MPI.
1287  return;
1288  }
1289 
1290  numPacketsPerLID.sync_host ();
1291  numPacketsPerLID.modify_host ();
1292 
1293  TEUCHOS_ASSERT( ! exportLIDs.need_sync_host () );
1294  auto exportLIDs_h = exportLIDs.view_host ();
1295 
1296  int totalNumPackets = 0;
1297  size_t numInvalidRowInds = 0;
1298  std::ostringstream errStrm; // current loop iteration's error messages
1299  for (size_t k = 0; k < numExports; ++k) {
1300  const LO lclRow = exportLIDs_h[k];
1301  // We're packing the source object's data, so we need to use the
1302  // source object's Map to convert from local to global indices.
1303  const GO gblRow = src->map_->getGlobalElement (lclRow);
1304  if (gblRow == ::Tpetra::Details::OrdinalTraits<GO>::invalid ()) {
1305  // Mark the error later; just count for now.
1306  ++numInvalidRowInds;
1307  numPacketsPerLID.h_view[k] = 0;
1308  continue;
1309  }
1310 
1311  // Count the number of bytes needed to pack the current row of
1312  // the source object.
1313  int numPackets = 0;
1314  const int errCode =
1315  src->impl_.countPackRow (numPackets, gblRow, *comm, &errStrm);
1316  if (errCode != 0) {
1317  std::ostream& err = this->markLocalErrorAndGetStream ();
1318  err << prefix << errStrm.str () << endl;
1319  numPacketsPerLID.h_view[k] = 0;
1320  continue;
1321  }
1322 
1323  // Make sure that the total number of packets fits in int.
1324  // MPI requires this.
1325  const long long newTotalNumPackets =
1326  static_cast<long long> (totalNumPackets) +
1327  static_cast<long long> (numPackets);
1328  if (newTotalNumPackets >
1329  static_cast<long long> (std::numeric_limits<int>::max ())) {
1330  std::ostream& err = this->markLocalErrorAndGetStream ();
1331  err << prefix << "The new total number of packets "
1332  << newTotalNumPackets << " does not fit in int." << endl;
1333  // At this point, we definitely cannot continue. In order to
1334  // leave the output arguments in a rational state, we zero out
1335  // all remaining entries of numPacketsPerLID before returning.
1336  for (size_t k2 = k; k2 < numExports; ++k2) {
1337  numPacketsPerLID.h_view[k2] = 0;
1338  }
1339  return;
1340  }
1341  numPacketsPerLID.h_view[k] = static_cast<size_t> (numPackets);
1342  totalNumPackets = static_cast<int> (newTotalNumPackets);
1343  }
1344 
1345  // If we found invalid row indices in exportLIDs, go back,
1346  // collect, and report them.
1347  if (numInvalidRowInds != 0) {
1348  std::vector<std::pair<LO, GO> > invalidRowInds;
1349  for (size_t k = 0; k < numExports; ++k) {
1350  const LO lclRow = exportLIDs_h[k];
1351  // We're packing the source object's data, so we need to use
1352  // the source object's Map to convert from local to global
1353  // indices.
1354  const GO gblRow = src->map_->getGlobalElement (lclRow);
1355  if (gblRow == ::Tpetra::Details::OrdinalTraits<GO>::invalid ()) {
1356  invalidRowInds.push_back ({lclRow, gblRow});
1357  }
1358  }
1359  std::ostringstream os;
1360  os << prefix << "We found " << numInvalidRowInds << " invalid row ind"
1361  << (numInvalidRowInds != static_cast<size_t> (1) ? "ices" : "ex")
1362  << " out of " << numExports << " in exportLIDs. Here is the list "
1363  << " of invalid row indices: [";
1364  for (size_t k = 0; k < invalidRowInds.size (); ++k) {
1365  os << "(LID: " << invalidRowInds[k].first << ", GID: "
1366  << invalidRowInds[k].second << ")";
1367  if (k + 1 < invalidRowInds.size ()) {
1368  os << ", ";
1369  }
1370  }
1371  os << "].";
1372 
1373  std::ostream& err = this->markLocalErrorAndGetStream ();
1374  err << prefix << os.str () << std::endl;
1375  return;
1376  }
1377 
1378  {
1379  const bool reallocated =
1380  Details::reallocDualViewIfNeeded (exports, totalNumPackets,
1381  "CooMatrix exports");
1382  if (reallocated) {
1383  exports.sync_host (); // make sure alloc'd on host
1384  }
1385  }
1386  exports.modify_host ();
1387 
1388  // FIXME (mfh 17 Jan 2017) packTriples wants three arrays, not a
1389  // single array of structs. For now, we just copy.
1390  std::vector<GO> gblRowInds;
1391  std::vector<GO> gblColInds;
1392  std::vector<SC> vals;
1393 
1394  int outBufCurPos = 0;
1395  packet_type* outBuf = exports.h_view.data ();
1396  for (size_t k = 0; k < numExports; ++k) {
1397  const LO lclRow = exportLIDs.h_view[k];
1398  // We're packing the source object's data, so we need to use the
1399  // source object's Map to convert from local to global indices.
1400  const GO gblRow = src->map_->getGlobalElement (lclRow);
1401  // Pack the current row of the source object.
1402  src->impl_.packRow (outBuf, totalNumPackets, outBufCurPos, *comm,
1403  gblRowInds, gblColInds, vals, gblRow);
1404  }
1405  }
1406 
1407  virtual void
1408 #ifdef TPETRA_ENABLE_DEPRECATED_CODE
1409  unpackAndCombineNew
1410 #else // TPETRA_ENABLE_DEPRECATED_CODE
1411  unpackAndCombine
1412 #endif // TPETRA_ENABLE_DEPRECATED_CODE
1413  (const Kokkos::DualView<const local_ordinal_type*,
1414  buffer_device_type>& importLIDs,
1415  Kokkos::DualView<packet_type*,
1416  buffer_device_type> imports,
1417  Kokkos::DualView<size_t*,
1418  buffer_device_type> numPacketsPerLID,
1419  const size_t /* constantNumPackets */,
1420  ::Tpetra::Distributor& /* distor */,
1421  const ::Tpetra::CombineMode /* combineMode */)
1422  {
1423  using Teuchos::Comm;
1424  using Teuchos::RCP;
1425  using std::endl;
1426  const char prefix[] = "Tpetra::Details::CooMatrix::unpackAndCombine: ";
1427  const char suffix[] = " This should never happen. "
1428  "Please report this bug to the Tpetra developers.";
1429 
1430  TEUCHOS_ASSERT( ! importLIDs.need_sync_host () );
1431  auto importLIDs_h = importLIDs.view_host ();
1432 
1433  const std::size_t numImports = importLIDs.extent (0);
1434  if (numImports == 0) {
1435  return; // nothing to receive
1436  }
1437  else if (imports.extent (0) == 0) {
1438  std::ostream& err = this->markLocalErrorAndGetStream ();
1439  err << prefix << "importLIDs.extent(0) = " << numImports << " != 0, "
1440  << "but imports.extent(0) = 0. This doesn't make sense, because "
1441  << "for every incoming LID, CooMatrix packs at least the count of "
1442  << "triples associated with that LID, even if the count is zero. "
1443  << "importLIDs = [";
1444  for (std::size_t k = 0; k < numImports; ++k) {
1445  err << importLIDs_h[k];
1446  if (k + 1 < numImports) {
1447  err << ", ";
1448  }
1449  }
1450  err << "]. " << suffix << endl;
1451  return;
1452  }
1453 
1454  RCP<const Comm<int> > comm = this->getMap ().is_null () ?
1455  Teuchos::null : this->getMap ()->getComm ();
1456  if (comm.is_null () || comm->getSize () == 1) {
1457  if (numImports != static_cast<size_t> (0)) {
1458  std::ostream& err = this->markLocalErrorAndGetStream ();
1459  err << prefix << "The input communicator is either null or "
1460  "has only one process, but numImports = " << numImports << " != 0."
1461  << suffix << endl;
1462  return;
1463  }
1464  // Don't go into the rest of this method unless there are
1465  // actually processes other than the calling process. This is
1466  // because the pack and unpack functions only have nonstub
1467  // implementations if building with MPI.
1468  return;
1469  }
1470 
1471  // Make sure that the length of 'imports' fits in int.
1472  // This is ultimately an MPI restriction.
1473  if (static_cast<size_t> (imports.extent (0)) >
1474  static_cast<size_t> (std::numeric_limits<int>::max ())) {
1475  std::ostream& err = this->markLocalErrorAndGetStream ();
1476  err << prefix << "imports.extent(0) = "
1477  << imports.extent (0) << " does not fit in int." << endl;
1478  return;
1479  }
1480  const int inBufSize = static_cast<int> (imports.extent (0));
1481 
1482  if (imports.need_sync_host ()) {
1483  imports.sync_host ();
1484  }
1485  if (numPacketsPerLID.need_sync_host ()) {
1486  numPacketsPerLID.sync_host ();
1487  }
1488  auto imports_h = imports.view_host ();
1489  auto numPacketsPerLID_h = numPacketsPerLID.view_host ();
1490 
1491  // FIXME (mfh 17,24 Jan 2017) packTriples wants three arrays, not a
1492  // single array of structs. For now, we just copy.
1493  std::vector<GO> gblRowInds;
1494  std::vector<GO> gblColInds;
1495  std::vector<SC> vals;
1496 
1497  const packet_type* inBuf = imports_h.data ();
1498  int inBufCurPos = 0;
1499  size_t numInvalidRowInds = 0;
1500  int errCode = 0;
1501  std::ostringstream errStrm; // for unpack* error output.
1502  for (size_t k = 0; k < numImports; ++k) {
1503  const LO lclRow = importLIDs_h(k);
1504  const GO gblRow = this->map_->getGlobalElement (lclRow);
1505  if (gblRow == ::Tpetra::Details::OrdinalTraits<GO>::invalid ()) {
1506  ++numInvalidRowInds;
1507  continue;
1508  }
1509 
1510  // Remember where we were, so we don't overrun the buffer
1511  // length. inBufCurPos is an in/out argument of unpackTriples*.
1512  const int origInBufCurPos = inBufCurPos;
1513 
1514  int numEnt = 0; // output argument of unpackTriplesCount
1515  errCode = unpackTriplesCount (inBuf, inBufSize, inBufCurPos,
1516  numEnt, *comm, &errStrm);
1517  if (errCode != 0 || numEnt < 0 || inBufCurPos < origInBufCurPos) {
1518  std::ostream& err = this->markLocalErrorAndGetStream ();
1519 
1520  err << prefix << "In unpack loop, k=" << k << ": ";
1521  if (errCode != 0) {
1522  err << " unpackTriplesCount returned errCode = " << errCode
1523  << " != 0." << endl;
1524  }
1525  if (numEnt < 0) {
1526  err << " unpackTriplesCount returned errCode = 0, but numEnt = "
1527  << numEnt << " < 0." << endl;
1528  }
1529  if (inBufCurPos < origInBufCurPos) {
1530  err << " After unpackTriplesCount, inBufCurPos = " << inBufCurPos
1531  << " < origInBufCurPos = " << origInBufCurPos << "." << endl;
1532  }
1533  err << " unpackTriplesCount report: " << errStrm.str () << endl;
1534  err << suffix << endl;
1535 
1536  // We only continue in a debug build, because the above error
1537  // messages could consume too much memory and cause an
1538  // out-of-memory error, without actually printing. Printing
1539  // everything is useful in a debug build, but not so much in a
1540  // release build.
1541 #ifdef HAVE_TPETRA_DEBUG
1542  // Clear out the current error stream, so we don't accumulate
1543  // over loop iterations.
1544  errStrm.str ("");
1545  continue;
1546 #else
1547  return;
1548 #endif // HAVE_TPETRA_DEBUG
1549  }
1550 
1551  // FIXME (mfh 17,24 Jan 2017) packTriples wants three arrays,
1552  // not a single array of structs. For now, we just copy.
1553  gblRowInds.resize (numEnt);
1554  gblColInds.resize (numEnt);
1555  vals.resize (numEnt);
1556 
1557  errCode = unpackTriples (inBuf, inBufSize, inBufCurPos,
1558  gblRowInds.data (), gblColInds.data (),
1559  vals.data (), numEnt, *comm, &errStrm);
1560  if (errCode != 0) {
1561  std::ostream& err = this->markLocalErrorAndGetStream ();
1562  err << prefix << "unpackTriples returned errCode = "
1563  << errCode << " != 0. It reports: " << errStrm.str ()
1564  << endl;
1565  // We only continue in a debug build, because the above error
1566  // messages could consume too much memory and cause an
1567  // out-of-memory error, without actually printing. Printing
1568  // everything is useful in a debug build, but not so much in a
1569  // release build.
1570 #ifdef HAVE_TPETRA_DEBUG
1571  // Clear out the current error stream, so we don't accumulate
1572  // over loop iterations.
1573  errStrm.str ("");
1574  continue;
1575 #else
1576  return;
1577 #endif // HAVE_TPETRA_DEBUG
1578  }
1579  this->sumIntoGlobalValues (gblRowInds.data (), gblColInds.data (),
1580  vals.data (), numEnt);
1581  }
1582 
1583  // If we found invalid row indices in exportLIDs, go back,
1584  // collect, and report them.
1585  if (numInvalidRowInds != 0) {
1586  // Mark the error now, before we possibly run out of memory.
1587  // The latter could raise an exception (e.g., std::bad_alloc),
1588  // but at least we would get the error state right.
1589  std::ostream& err = this->markLocalErrorAndGetStream ();
1590 
1591  std::vector<std::pair<LO, GO> > invalidRowInds;
1592  for (size_t k = 0; k < numImports; ++k) {
1593  const LO lclRow = importLIDs_h(k);
1594  const GO gblRow = this->map_->getGlobalElement (lclRow);
1595  if (gblRow == ::Tpetra::Details::OrdinalTraits<GO>::invalid ()) {
1596  invalidRowInds.push_back ({lclRow, gblRow});
1597  }
1598  }
1599 
1600  err << prefix << "We found " << numInvalidRowInds << " invalid row ind"
1601  << (numInvalidRowInds != static_cast<size_t> (1) ? "ices" : "ex")
1602  << " out of " << numImports << " in importLIDs. Here is the list "
1603  << " of invalid row indices: [";
1604  for (size_t k = 0; k < invalidRowInds.size (); ++k) {
1605  err << "(LID: " << invalidRowInds[k].first << ", GID: "
1606  << invalidRowInds[k].second << ")";
1607  if (k + 1 < invalidRowInds.size ()) {
1608  err << ", ";
1609  }
1610  }
1611  err << "].";
1612  return;
1613  }
1614  }
1615 };
1616 
1617 } // namespace Details
1618 } // namespace Tpetra
1619 
1620 #endif // TPETRA_DETAILS_COOMATRIX_HPP
Tpetra::Details::unpackTriples
int unpackTriples(const char[], const int, int &, OrdinalType[], OrdinalType[], ScalarType[], const int, const ::Teuchos::Comm< int > &, std::ostream *errStrm=NULL)
Unpack matrix entries ("triples" (i, j, A(i,j))) from the given input buffer.
Definition: Tpetra_Details_PackTriples.hpp:579
Tpetra::Details::CooMatrix::fillComplete
void fillComplete(const ::Teuchos::RCP< const ::Teuchos::Comm< int > > &comm)
Tell the matrix that you are done inserting entries locally, and that the matrix should build its Map...
Definition: Tpetra_Details_CooMatrix.hpp:717
Tpetra::Details::CooMatrix::sumIntoGlobalValue
void sumIntoGlobalValue(const GO gblRowInd, const GO gblColInd, const SC &val)
Insert one entry locally into the sparse matrix, if it does not exist there yet. If it does exist,...
Definition: Tpetra_Details_CooMatrix.hpp:630
Tpetra::Details::Impl::CooGraphEntry
Type of each (row index, column index) pair in the Tpetra::Details::CooMatrix (see below).
Definition: Tpetra_Details_CooMatrix.hpp:75
Tpetra::Details::CooMatrix::buffer_device_type
typename ::Tpetra::DistObject< char, LO, GO, NT >::buffer_device_type buffer_device_type
Kokkos::Device specialization for DistObject communication buffers.
Definition: Tpetra_Details_CooMatrix.hpp:999
Tpetra::Details::CooMatrix::errorMessages
std::string errorMessages() const
The current stream of error messages.
Definition: Tpetra_Details_CooMatrix.hpp:781
Tpetra::Details::Impl::CooMatrixImpl::sumIntoGlobalValue
void sumIntoGlobalValue(const GO gblRowInd, const GO gblColInd, const SC &val)
Insert one entry locally into the sparse matrix, if it does not exist there yet. If it does exist,...
Definition: Tpetra_Details_CooMatrix.hpp:127
Tpetra::Details::CooMatrix::CooMatrix
CooMatrix()
Default constructor.
Definition: Tpetra_Details_CooMatrix.hpp:601
Tpetra::Details::Impl::CooMatrixImpl::forAllEntries
void forAllEntries(std::function< void(const GO, const GO, const SC &)> f) const
Execute the given function for all entries of the sparse matrix, sequentially (no thread parallelism)...
Definition: Tpetra_Details_CooMatrix.hpp:179
Tpetra::Details::CooMatrix::sumIntoGlobalValues
void sumIntoGlobalValues(const GO gblRowInds[], const GO gblColInds[], const SC vals[], const std::size_t numEnt)
Insert multiple entries locally into the sparse matrix.
Definition: Tpetra_Details_CooMatrix.hpp:646
Tpetra::DistObject::local_ordinal_type
LocalOrdinal local_ordinal_type
The type of local indices.
Definition: Tpetra_DistObject_decl.hpp:340
Tpetra::Details::CooMatrix
Sparse matrix used only for file input / output.
Definition: Tpetra_Details_CooMatrix.hpp:574
Tpetra::Details::CooMatrix::packet_type
char packet_type
This class transfers data as bytes (MPI_BYTE).
Definition: Tpetra_Details_CooMatrix.hpp:577
Tpetra::Details::Impl::CooMatrixImpl::buildLocallyIndexedCrs
void buildLocallyIndexedCrs(std::vector< OffsetType > &rowOffsets, LO lclColInds[], SC vals[], std::function< LO(const GO)> gblToLcl) const
Build a locally indexed version of CRS storage.
Definition: Tpetra_Details_CooMatrix.hpp:480
Tpetra::DistObject
Base class for distributed Tpetra objects that support data redistribution.
Definition: Tpetra_DistObject_decl.hpp:329
Details
Implementation details of Tpetra.
Tpetra::Details::gathervPrint
void gathervPrint(std::ostream &out, const std::string &s, const Teuchos::Comm< int > &comm)
On Process 0 in the given communicator, print strings from each process in that communicator,...
Definition: Tpetra_Details_gathervPrint.cpp:52
Tpetra::Details::CooMatrix::fillComplete
void fillComplete()
Special version of fillComplete that assumes that the matrix already has a Map, and reuses its commun...
Definition: Tpetra_Details_CooMatrix.hpp:736
Tpetra::DistObject::node_type
Node node_type
The Node type. If you don't know what this is, don't use it.
Definition: Tpetra_DistObject_decl.hpp:344
Tpetra::DistObject< char, ::Tpetra::DistObject< char >::local_ordinal_type, ::Tpetra::DistObject< char >::global_ordinal_type, ::Tpetra::DistObject< char >::node_type >::map_
Teuchos::RCP< const map_type > map_
The Map over which this object is distributed.
Definition: Tpetra_DistObject_decl.hpp:1133
Tpetra::Details::Impl::CooMatrixImpl
Implementation detail of Tpetra::Details::CooMatrix (which see below).
Definition: Tpetra_Details_CooMatrix.hpp:97
Tpetra::Details::Impl::CooMatrixImpl::getMyGlobalRowIndices
GO getMyGlobalRowIndices(std::vector< GO > &rowInds) const
Get the global row indices on this process, sorted and made unique, and return the minimum global row...
Definition: Tpetra_Details_CooMatrix.hpp:407
Tpetra::Details::CooMatrix::scalar_type
SC scalar_type
Type of each entry (value) in the sparse matrix.
Definition: Tpetra_Details_CooMatrix.hpp:579
Tpetra::Details::CooMatrix::description
virtual std::string description() const
One-line descriptiion of this object; overrides Teuchos::Describable method.
Definition: Tpetra_Details_CooMatrix.hpp:823
Tpetra::Details::packTriplesCount
int packTriplesCount(const int, char[], const int, int &, const ::Teuchos::Comm< int > &, std::ostream *errStrm)
Pack the count (number) of matrix triples.
Definition: Tpetra_Details_PackTriples.cpp:201
Tpetra::Details::CooMatrix::~CooMatrix
virtual ~CooMatrix()
Destructor (virtual for memory safety of derived classes).
Definition: Tpetra_Details_CooMatrix.hpp:621
Tpetra::Details::CooMatrix::sumIntoGlobalValues
void sumIntoGlobalValues(std::initializer_list< GO > gblRowInds, std::initializer_list< GO > gblColInds, std::initializer_list< SC > vals, const std::size_t numEnt)
Initializer-list overload of the above method (which see).
Definition: Tpetra_Details_CooMatrix.hpp:656
Tpetra::Details::Impl::CooMatrixImpl::packet_type
char packet_type
Type for packing and unpacking data.
Definition: Tpetra_Details_CooMatrix.hpp:115
Tpetra::Distributor
Sets up and executes a communication plan for a Tpetra DistObject.
Definition: Tpetra_Distributor.hpp:192
Tpetra::Details::Impl::CooMatrixImpl::CooMatrixImpl
CooMatrixImpl()=default
Default constructor.
Tpetra::Details::CooMatrix::localError
bool localError() const
Whether this object had an error on the calling process.
Definition: Tpetra_Details_CooMatrix.hpp:760
Tpetra::Details::Impl::CooMatrixImpl::packRow
void packRow(packet_type outBuf[], const int outBufSize, int &outBufCurPos, const ::Teuchos::Comm< int > &comm, std::vector< GO > &gblRowInds, std::vector< GO > &gblColInds, std::vector< SC > &vals, const GO gblRow) const
Pack the given row of the matrix.
Definition: Tpetra_Details_CooMatrix.hpp:338
Tpetra::Details::DefaultTypes::local_ordinal_type
int local_ordinal_type
Default value of Scalar template parameter.
Definition: Tpetra_Details_DefaultTypes.hpp:72
Tpetra::Details::Impl::CooMatrixImpl::getLclNumEntries
std::size_t getLclNumEntries() const
Number of entries in the sparse matrix on the calling process.
Definition: Tpetra_Details_CooMatrix.hpp:170
Tpetra::Details::Impl::CooMatrixImpl::mergeIntoRow
void mergeIntoRow(const GO tgtGblRow, const CooMatrixImpl< SC, GO > &src, const GO srcGblRow)
Into global row tgtGblRow of *this, merge global row srcGblRow of src.
Definition: Tpetra_Details_CooMatrix.hpp:193
Tpetra::Details::unpackTriplesCount
int unpackTriplesCount(const char[], const int, int &, int &, const ::Teuchos::Comm< int > &, std::ostream *errStrm)
Unpack just the count of triples from the given input buffer.
Definition: Tpetra_Details_PackTriples.cpp:232
Tpetra::Details::countPackTriplesCount
int countPackTriplesCount(const ::Teuchos::Comm< int > &, int &size, std::ostream *errStrm)
Compute the buffer size required by packTriples for packing the number of matrix entries ("triples").
Definition: Tpetra_Details_PackTriples.cpp:173
Tpetra::Details::Impl::CooMatrixImpl::countPackRow
int countPackRow(int &numPackets, const GO gblRow, const ::Teuchos::Comm< int > &comm, std::ostream *errStrm=NULL) const
Count the number of packets (bytes, in this case) needed to pack the given row of the matrix.
Definition: Tpetra_Details_CooMatrix.hpp:255
Tpetra::Details::Impl::CompareCooGraphEntries
Function comparing two CooGraphEntry structs, lexicographically, first by row index,...
Definition: Tpetra_Details_CooMatrix.hpp:85
Tpetra::DistObject< char, ::Tpetra::DistObject< char >::local_ordinal_type, ::Tpetra::DistObject< char >::global_ordinal_type, ::Tpetra::DistObject< char >::node_type >::getMap
virtual Teuchos::RCP< const map_type > getMap() const
The Map describing the parallel distribution of this object.
Definition: Tpetra_DistObject_decl.hpp:541
Tpetra_Details_reallocDualViewIfNeeded.hpp
Declaration and definition of Tpetra::Details::reallocDualViewIfNeeded, an implementation detail of T...
Tpetra::Details::Impl::CooMatrixImpl::sumIntoGlobalValues
void sumIntoGlobalValues(const GO gblRowInds[], const GO gblColInds[], const SC vals[], const std::size_t numEnt)
Insert multiple entries locally into the sparse matrix.
Definition: Tpetra_Details_CooMatrix.hpp:150
Tpetra::Details::CooMatrix::describe
virtual void describe(Teuchos::FancyOStream &out, const Teuchos::EVerbosityLevel verbLevel=Teuchos::Describable::verbLevel_default) const
Print a descriptiion of this object to the given output stream; overrides Teuchos::Describable method...
Definition: Tpetra_Details_CooMatrix.hpp:843
Tpetra::Details::CooMatrix::checkSizes
virtual bool checkSizes(const ::Tpetra::SrcDistObject &source)
Compare the source and target (this) objects for compatibility.
Definition: Tpetra_Details_CooMatrix.hpp:975
Tpetra::Details::CooMatrix::constantNumberOfPackets
virtual size_t constantNumberOfPackets() const
By returning 0, tell DistObject that this class may not necessarily have a constant number of "packet...
Definition: Tpetra_Details_CooMatrix.hpp:967
Tpetra::Details::CooMatrix::map_type
::Tpetra::Map< local_ordinal_type, global_ordinal_type, node_type > map_type
Type of the Map specialization to give to the constructor.
Definition: Tpetra_Details_CooMatrix.hpp:585
Tpetra
Namespace Tpetra contains the class and methods constituting the Tpetra library.
Tpetra::deep_copy
void deep_copy(MultiVector< DS, DL, DG, DN > &dst, const MultiVector< SS, SL, SG, SN > &src)
Copy the contents of the MultiVector src into dst.
Definition: Tpetra_MultiVector_decl.hpp:2557
Tpetra::Details::CooMatrix::CooMatrix
CooMatrix(const ::Teuchos::RCP< const map_type > &map)
Constructor that takes a Map.
Definition: Tpetra_Details_CooMatrix.hpp:614
Tpetra::Details::packTriples
int packTriples(const OrdinalType[], const OrdinalType[], const ScalarType[], const int, char[], const int, int &, const ::Teuchos::Comm< int > &, std::ostream *errStrm=NULL)
Pack matrix entries ("triples" (i, j, A(i,j))) into the given output buffer.
Definition: Tpetra_Details_PackTriples.hpp:463
Tpetra::Details::CooMatrix::getLclNumEntries
std::size_t getLclNumEntries() const
Number of entries in the sparse matrix on the calling process.
Definition: Tpetra_Details_CooMatrix.hpp:667
Tpetra::Details::reallocDualViewIfNeeded
bool reallocDualViewIfNeeded(Kokkos::DualView< ValueType *, DeviceType > &dv, const size_t newSize, const char newLabel[], const size_t tooBigFactor=2, const bool needFenceBeforeRealloc=true)
Reallocate the DualView in/out argument, if needed.
Definition: Tpetra_Details_reallocDualViewIfNeeded.hpp:83
Tpetra::CombineMode
CombineMode
Rule for combining data in an Import or Export.
Definition: Tpetra_CombineMode.hpp:94
Tpetra::DistObject::global_ordinal_type
GlobalOrdinal global_ordinal_type
The type of global indices.
Definition: Tpetra_DistObject_decl.hpp:342