Tpetra parallel linear algebra Version of the Day
Loading...
Searching...
No Matches
Tpetra_Details_CooMatrix.hpp
Go to the documentation of this file.
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_DETAILS_COOMATRIX_HPP
11#define TPETRA_DETAILS_COOMATRIX_HPP
12
17
18#include "TpetraCore_config.h"
19#include "Tpetra_Details_PackTriples.hpp"
20#include "Tpetra_DistObject.hpp"
23#include "Teuchos_TypeNameTraits.hpp"
24
25#include <initializer_list>
26#include <map>
27#include <memory>
28#include <string>
29#include <type_traits>
30#include <vector>
31
32namespace Tpetra {
33namespace Details {
34
35// Implementation details of Tpetra::Details.
36// So, users REALLY should not use anything in here.
37namespace Impl {
38
41template <class IndexType>
43 IndexType row;
44 IndexType col;
45};
46
51template <class IndexType>
53 bool
54 operator()(const CooGraphEntry<IndexType>& x,
55 const CooGraphEntry<IndexType>& y) const {
56 return (x.row < y.row) || (x.row == y.row && x.col < y.col);
57 }
58};
59
62template <class SC, class GO>
64 private:
72 typedef std::map<CooGraphEntry<GO>, SC,
74 entries_type;
75
78 entries_type entries_;
79
80 public:
82 typedef char packet_type;
83
85 CooMatrixImpl() = default;
86
93 void
95 const GO gblColInd,
96 const SC& val) {
97 // There's no sense in worrying about the insertion hint, since
98 // indices may be all over the place. Users make no promises of
99 // sorting or locality of input.
101 auto result = this->entries_.insert({ij, val});
102 if (!result.second) { // already in the map
103 result.first->second += val; // sum in the new value
104 }
105 }
106
115 void
117 const GO gblColInds[],
118 const SC vals[],
119 const std::size_t numEnt) {
120 for (std::size_t k = 0; k < numEnt; ++k) {
121 // There's no sense in worrying about the insertion hint, since
122 // indices may be all over the place. Users make no promises of
123 // sorting or locality of input.
125 const SC val = vals[k];
126 auto result = this->entries_.insert({ij, val});
127 if (!result.second) { // already in the map
128 result.first->second += val; // sum in the new value
129 }
130 }
131 }
132
134 std::size_t
136 return this->entries_.size();
137 }
138
142 void
143 forAllEntries(std::function<void(const GO, const GO, const SC&)> f) const {
144 for (auto iter = this->entries_.begin();
145 iter != this->entries_.end(); ++iter) {
146 f(iter->first.row, iter->first.col, iter->second);
147 }
148 }
149
155 void
157 const CooMatrixImpl<SC, GO>& src,
158 const GO srcGblRow) {
159 // const char prefix[] =
160 // "Tpetra::Details::Impl::CooMatrixImpl::mergeIntoRow: ";
161
162 entries_type& tgtEntries = this->entries_;
163 const entries_type& srcEntries = src.entries_;
164
165 // Find all entries with the given global row index. The min GO
166 // value is guaranteed to be the least possible column index, so
167 // beg1 is a lower bound for all (row index, column index) pairs.
168 // Lower bound is inclusive; upper bound is exclusive.
169 auto srcBeg = srcEntries.lower_bound({srcGblRow, std::numeric_limits<GO>::min()});
170 auto srcEnd = srcEntries.upper_bound({srcGblRow + 1, std::numeric_limits<GO>::min()});
171 auto tgtBeg = tgtEntries.lower_bound({tgtGblRow, std::numeric_limits<GO>::min()});
172 auto tgtEnd = tgtEntries.upper_bound({tgtGblRow + 1, std::numeric_limits<GO>::min()});
173
174 // Don't waste time iterating over the current row of *this, if
175 // the current row of src is empty.
176 if (srcBeg != srcEnd) {
177 for (auto tgtCur = tgtBeg; tgtCur != tgtEnd; ++tgtCur) {
178 auto srcCur = srcBeg;
179 while (srcCur != srcEnd && srcCur->first.col < tgtCur->first.col) {
180 ++srcCur;
181 }
182 // At this point, one of the following is true:
183 //
184 // 1. srcCur == srcEnd, thus nothing more to insert.
185 // 2. srcCur->first.col > tgtCur->first.col, thus the current
186 // row of src has no entry matching tgtCur->first, so we
187 // have to insert it. Insertion does not invalidate
188 // tgtEntries iterators, and neither srcEntries nor
189 // tgtEntries have duplicates, so this is safe.
190 // 3. srcCur->first.col == tgtCur->first.col, so add the two entries.
191 if (srcCur != srcEnd) {
192 if (srcCur->first.col == tgtCur->first.col) {
193 tgtCur->second += srcCur->second;
194 } else {
195 // tgtCur is (optimally) right before where we want to put
196 // the new entry, since srcCur points to the first entry
197 // in srcEntries whose column index is greater than that
198 // of the entry to which tgtCur points.
199 (void)tgtEntries.insert(tgtCur, *srcCur);
200 }
201 } // if srcCur != srcEnd
202 } // for each entry in the current row (lclRow) of *this
203 } // if srcBeg != srcEnd
204 }
205
217 const GO gblRow,
218 const ::Teuchos::Comm<int>& comm,
219 std::ostream* errStrm = NULL) const {
220 using std::endl;
221 using ::Tpetra::Details::countPackTriples;
222 using ::Tpetra::Details::countPackTriplesCount;
223 const char prefix[] = "Tpetra::Details::Impl::CooMatrixImpl::countPackRow: ";
224#ifdef HAVE_TPETRACORE_MPI
225 int errCode = MPI_SUCCESS;
226#else
227 int errCode = 0;
228#endif // HAVE_TPETRACORE_MPI
229
230 // Count the number of entries in the given row.
231 const GO minGO = std::numeric_limits<GO>::min();
232 auto beg = this->entries_.lower_bound({gblRow, minGO});
233 auto end = this->entries_.upper_bound({gblRow + 1, minGO});
234 int numEnt = 0;
235 for (auto iter = beg; iter != end; ++iter) {
236 ++numEnt;
237 if (numEnt == std::numeric_limits<int>::max()) {
238 if (errStrm != NULL) {
239 *errStrm << prefix << "In (global) row " << gblRow << ", the number "
240 "of entries thus far, numEnt = "
241 << numEnt << ", has reached the "
242 "maximum int value. We need to store this count as int for MPI's "
243 "sake."
244 << endl;
245 }
246 return -1;
247 }
248 }
249
250 int numPacketsForCount = 0; // output argument of countPackTriplesCount
251 {
252 errCode =
254 if (errCode != 0) {
255 if (errStrm != NULL) {
256 *errStrm << prefix << "countPackTriplesCount "
257 "returned errCode = "
258 << errCode << " != 0." << endl;
259 }
260 return errCode;
261 }
262 if (numPacketsForCount < 0) {
263 if (errStrm != NULL) {
264 *errStrm << prefix << "countPackTriplesCount returned "
265 "numPacketsForCount = "
266 << numPacketsForCount << " < 0." << endl;
267 }
268 return -1;
269 }
270 }
271
272 int numPacketsForTriples = 0; // output argument of countPackTriples
273 {
275 TEUCHOS_TEST_FOR_EXCEPTION(errCode != 0, std::runtime_error, prefix << "countPackTriples "
276 "returned errCode = "
277 << errCode << " != 0.");
278 TEUCHOS_TEST_FOR_EXCEPTION(numPacketsForTriples < 0, std::logic_error, prefix << "countPackTriples "
279 "returned numPacketsForTriples = "
280 << numPacketsForTriples << " < 0.");
281 }
282
284 return errCode;
285 }
286
301 void
303 const int outBufSize,
304 int& outBufCurPos, // in/out argument
305 const ::Teuchos::Comm<int>& comm,
306 std::vector<GO>& gblRowInds,
307 std::vector<GO>& gblColInds,
308 std::vector<SC>& vals,
309 const GO gblRow) const {
310 using ::Tpetra::Details::packTriples;
311 using ::Tpetra::Details::packTriplesCount;
312 const char prefix[] = "Tpetra::Details::Impl::CooMatrixImpl::packRow: ";
313
314 const GO minGO = std::numeric_limits<GO>::min();
315 auto beg = this->entries_.lower_bound({gblRow, minGO});
316 auto end = this->entries_.upper_bound({gblRow + 1, minGO});
317
318 // This doesn't actually deallocate. Only swapping with an empty
319 // std::vector does that.
320 gblRowInds.resize(0);
321 gblColInds.resize(0);
322 vals.resize(0);
323
324 int numEnt = 0;
325 for (auto iter = beg; iter != end; ++iter) {
326 gblRowInds.push_back(iter->first.row);
327 gblColInds.push_back(iter->first.col);
328 vals.push_back(iter->second);
329 ++numEnt;
330 TEUCHOS_TEST_FOR_EXCEPTION(numEnt == std::numeric_limits<int>::max(), std::runtime_error, prefix << "In (global) row " << gblRow << ", the number of entries thus far, "
331 "numEnt = "
332 << numEnt << ", has reached the maximum int value. "
333 "We need to store this count as int for MPI's sake.");
334 }
335
336 {
337 const int errCode =
339 TEUCHOS_TEST_FOR_EXCEPTION(errCode != 0, std::runtime_error, prefix << "In (global) row " << gblRow << ", packTriplesCount returned "
340 "errCode = "
341 << errCode << " != 0.");
342 }
343 {
344 const int errCode =
345 packTriples(gblRowInds.data(),
346 gblColInds.data(),
347 vals.data(),
348 numEnt,
349 outBuf,
351 outBufCurPos, // in/out argument
352 comm);
353 TEUCHOS_TEST_FOR_EXCEPTION(errCode != 0, std::runtime_error, prefix << "In (global) row " << gblRow << ", packTriples returned errCode = " << errCode << " != 0.");
354 }
355 }
356
364 GO getMyGlobalRowIndices(std::vector<GO>& rowInds) const {
365 rowInds.clear();
366
367 GO lclMinRowInd = std::numeric_limits<GO>::max(); // compute local min
368 for (typename entries_type::const_iterator iter = this->entries_.begin();
369 iter != this->entries_.end(); ++iter) {
370 const GO rowInd = iter->first.row;
371 if (rowInd < lclMinRowInd) {
373 }
374 if (rowInds.empty() || rowInds.back() != rowInd) {
375 rowInds.push_back(rowInd); // don't insert duplicates
376 }
377 }
378 return lclMinRowInd;
379 }
380
381 template <class OffsetType>
382 void
383 buildCrs(std::vector<OffsetType>& rowOffsets,
384 GO gblColInds[],
385 SC vals[]) const {
386 static_assert(std::is_integral<OffsetType>::value,
387 "OffsetType must be a built-in integer type.");
388
389 // clear() doesn't generally free storage; it just resets the
390 // length. Thus, we reuse any existing storage here.
391 rowOffsets.clear();
392
393 const std::size_t numEnt = this->getLclNumEntries();
394 if (numEnt == 0) {
395 rowOffsets.push_back(0);
396 } else {
397 typename entries_type::const_iterator iter = this->entries_.begin();
398 GO prevGblRowInd = iter->first.row;
399
400 OffsetType k = 0;
401 for (; iter != this->entries_.end(); ++iter, ++k) {
402 const GO gblRowInd = iter->first.row;
403 if (k == 0 || gblRowInd != prevGblRowInd) {
404 // The row offsets array always has at least one entry. The
405 // first entry is always zero, and the last entry is always
406 // the number of matrix entries.
407 rowOffsets.push_back(k);
409 }
410 gblColInds[k] = iter->first.col;
411
412 static_assert(std::is_same<typename std::decay<decltype(iter->second)>::type, SC>::value,
413 "The type of iter->second != SC.");
414 vals[k] = iter->second;
415 }
416 rowOffsets.push_back(static_cast<OffsetType>(numEnt));
417 }
418 }
419
432 template <class OffsetType, class LO>
433 void
434 buildLocallyIndexedCrs(std::vector<OffsetType>& rowOffsets,
435 LO lclColInds[],
436 SC vals[],
437 std::function<LO(const GO)> gblToLcl) const {
438 static_assert(std::is_integral<OffsetType>::value,
439 "OffsetType must be a built-in integer type.");
440 static_assert(std::is_integral<LO>::value,
441 "LO must be a built-in integer type.");
442
443 // clear() doesn't generally free storage; it just resets the
444 // length. Thus, we reuse any existing storage here.
445 rowOffsets.clear();
446
447 const std::size_t numEnt = this->getLclNumEntries();
448 if (numEnt == 0) {
449 rowOffsets.push_back(0);
450 } else {
451 typename entries_type::const_iterator iter = this->entries_.begin();
452 GO prevGblRowInd = iter->first.row;
453
454 OffsetType k = 0;
455 for (; iter != this->entries_.end(); ++iter, ++k) {
456 const GO gblRowInd = iter->first.row;
457 if (k == 0 || gblRowInd != prevGblRowInd) {
458 // The row offsets array always has at least one entry. The
459 // first entry is always zero, and the last entry is always
460 // the number of matrix entries.
461 rowOffsets.push_back(k);
463 }
464 lclColInds[k] = gblToLcl(iter->first.col);
465 vals[k] = iter->second;
466 }
467 rowOffsets.push_back(static_cast<OffsetType>(numEnt));
468 }
469 }
470};
471
472} // namespace Impl
473
522template <class SC,
526class CooMatrix : public ::Tpetra::DistObject<char, LO, GO, NT> {
527 public:
529 typedef char packet_type;
532 typedef LO local_ordinal_type;
533 typedef GO global_ordinal_type;
534 typedef NT node_type;
535 typedef typename NT::device_type device_type;
537 typedef ::Tpetra::Map<local_ordinal_type, global_ordinal_type, node_type> map_type;
538
539 private:
541 typedef ::Tpetra::DistObject<packet_type, local_ordinal_type,
542 global_ordinal_type, node_type>
543 base_type;
544
547
548 public:
555 : base_type(::Teuchos::null)
556 , localError_(new bool(false))
557 , errs_(new std::shared_ptr<std::ostringstream>()) // ptr to a null ptr
558 {}
559
567 CooMatrix(const ::Teuchos::RCP<const map_type>& map)
568 : base_type(map)
569 , localError_(new bool(false))
570 , errs_(new std::shared_ptr<std::ostringstream>()) // ptr to a null ptr
571 {}
572
574 virtual ~CooMatrix() {}
575
582 void
584 const GO gblColInd,
585 const SC& val) {
587 }
588
597 void
599 const GO gblColInds[],
600 const SC vals[],
601 const std::size_t numEnt) {
603 }
604
606 void
607 sumIntoGlobalValues(std::initializer_list<GO> gblRowInds,
608 std::initializer_list<GO> gblColInds,
609 std::initializer_list<SC> vals,
610 const std::size_t numEnt) {
611 this->impl_.sumIntoGlobalValues(gblRowInds.begin(), gblColInds.begin(),
612 vals.begin(), numEnt);
613 }
614
616 std::size_t
618 return this->impl_.getLclNumEntries();
619 }
620
621 template <class OffsetType>
622 void
623 buildCrs(::Kokkos::View<OffsetType*, device_type>& rowOffsets,
624 ::Kokkos::View<GO*, device_type>& gblColInds,
625 ::Kokkos::View<typename ::KokkosKernels::ArithTraits<SC>::val_type*, device_type>& vals) {
626 static_assert(std::is_integral<OffsetType>::value,
627 "OffsetType must be a built-in integer type.");
628 using ::Kokkos::create_mirror_view;
629 using ::Kokkos::deep_copy;
630 using ::Kokkos::View;
631 typedef typename ::KokkosKernels::ArithTraits<SC>::val_type ISC;
632
633 const std::size_t numEnt = this->getLclNumEntries();
634
635 gblColInds = View<GO*, device_type>("gblColInds", numEnt);
637 auto gblColInds_h = create_mirror_view(gblColInds);
638 auto vals_h = create_mirror_view(vals);
639
640 std::vector<std::size_t> rowOffsetsSV;
641 this->impl_.buildCrs(rowOffsetsSV,
642 gblColInds_h.data(),
643 vals_h.data());
644 rowOffsets =
645 View<OffsetType*, device_type>("rowOffsets", rowOffsetsSV.size());
647 rowOffsets_h(rowOffsetsSV.data(), rowOffsetsSV.size());
649
652 }
653
664 void
665 fillComplete(const ::Teuchos::RCP<const ::Teuchos::Comm<int> >& comm) {
666 if (comm.is_null()) {
667 this->map_ = ::Teuchos::null;
668 } else {
669 this->map_ = this->buildMap(comm);
670 }
671 }
672
681 void
683 TEUCHOS_TEST_FOR_EXCEPTION(this->getMap().is_null(), std::runtime_error,
684 "Tpetra::Details::"
685 "CooMatrix::fillComplete: This object does not yet have a Map. "
686 "You must call the version of fillComplete "
687 "that takes an input communicator.");
688 this->fillComplete(this->getMap()->getComm());
689 }
690
705 bool localError() const {
706 return *localError_;
707 }
708
726 std::string errorMessages() const {
727 return ((*errs_).get() == NULL) ? std::string("") : (*errs_)->str();
728 }
729
730 private:
743 std::shared_ptr<bool> localError_;
744
752 std::shared_ptr<std::shared_ptr<std::ostringstream> > errs_;
753
755 std::ostream&
756 markLocalErrorAndGetStream() {
757 *(this->localError_) = true;
758 if ((*errs_).get() == NULL) {
759 *errs_ = std::shared_ptr<std::ostringstream>(new std::ostringstream());
760 }
761 return **errs_;
762 }
763
764 public:
767 virtual std::string description() const {
768 using Teuchos::TypeNameTraits;
769
770 std::ostringstream os;
771 os << "\"Tpetra::Details::CooMatrix\": {"
772 << "SC: " << TypeNameTraits<SC>::name()
773 << ", LO: " << TypeNameTraits<LO>::name()
774 << ", GO: " << TypeNameTraits<GO>::name()
775 << ", NT: " << TypeNameTraits<NT>::name();
776 if (this->getObjectLabel() != "") {
777 os << ", Label: \"" << this->getObjectLabel() << "\"";
778 }
779 os << ", Has Map: " << (this->map_.is_null() ? "false" : "true")
780 << "}";
781 return os.str();
782 }
783
786 virtual void
787 describe(Teuchos::FancyOStream& out,
788 const Teuchos::EVerbosityLevel verbLevel =
789 Teuchos::Describable::verbLevel_default) const {
790 using std::endl;
791 using ::Teuchos::EVerbosityLevel;
792 using ::Teuchos::OSTab;
793 using ::Teuchos::TypeNameTraits;
794 using ::Teuchos::VERB_DEFAULT;
795 using ::Teuchos::VERB_LOW;
796 using ::Teuchos::VERB_MEDIUM;
797 using ::Tpetra::Details::gathervPrint;
798
799 const auto vl = (verbLevel == VERB_DEFAULT) ? VERB_LOW : verbLevel;
800
801 auto comm = this->getMap().is_null() ? Teuchos::null : this->getMap()->getComm();
802 const int myRank = comm.is_null() ? 0 : comm->getRank();
803 // const int numProcs = comm.is_null () ? 1 : comm->getSize ();
804
805 if (vl != Teuchos::VERB_NONE) {
806 // Convention is to start describe() implementations with a tab.
807 OSTab tab0(out);
808 if (myRank == 0) {
809 out << "\"Tpetra::Details::CooMatrix\":" << endl;
810 }
811 OSTab tab1(out);
812 if (myRank == 0) {
813 out << "Template parameters:" << endl;
814 {
815 OSTab tab2(out);
816 out << "SC: " << TypeNameTraits<SC>::name() << endl
817 << "LO: " << TypeNameTraits<LO>::name() << endl
818 << "GO: " << TypeNameTraits<GO>::name() << endl
819 << "NT: " << TypeNameTraits<NT>::name() << endl;
820 }
821 if (this->getObjectLabel() != "") {
822 out << "Label: \"" << this->getObjectLabel() << "\"" << endl;
823 }
824 out << "Has Map: " << (this->map_.is_null() ? "false" : "true") << endl;
825 } // if myRank == 0
826
827 // Describe the Map, if it exists.
828 if (!this->map_.is_null()) {
829 if (myRank == 0) {
830 out << "Map:" << endl;
831 }
832 OSTab tab2(out);
833 this->map_->describe(out, vl);
834 }
835
836 // At verbosity > VERB_LOW, each process prints something.
837 if (vl > VERB_LOW) {
838 std::ostringstream os;
839 os << "Process " << myRank << ":" << endl;
840 // OSTab tab3 (os);
841
842 const std::size_t numEnt = this->impl_.getLclNumEntries();
843 os << " Local number of entries: " << numEnt << endl;
844 if (vl > VERB_MEDIUM) {
845 os << " Local entries:" << endl;
846 // OSTab tab4 (os);
847 this->impl_.forAllEntries([&os](const GO row, const GO col, const SC& val) {
848 os << " {"
849 << "row: " << row
850 << ", col: " << col
851 << ", val: " << val
852 << "}" << endl;
853 });
854 }
855 gathervPrint(out, os.str(), *comm);
856 }
857 } // vl != Teuchos::VERB_NONE
858 }
859
860 private:
869 Teuchos::RCP<const map_type>
870 buildMap(const ::Teuchos::RCP<const ::Teuchos::Comm<int> >& comm) {
871 using ::Teuchos::outArg;
872 using ::Teuchos::rcp;
873 using ::Teuchos::REDUCE_MIN;
874 using ::Teuchos::reduceAll;
876 // const char prefix[] = "Tpetra::Details::CooMatrix::buildMap: ";
877
878 // Processes where comm is null don't participate in the Map.
879 if (comm.is_null()) {
880 return ::Teuchos::null;
881 }
882
883 // mfh 17 Jan 2017: We just happen to use row indices, because
884 // that's what Tpetra::CrsMatrix currently uses. That's probably
885 // not the best thing to use, but it's not bad for commonly
886 // encountered matrices. A better more general approach might be
887 // to hash (row index, column index) pairs to a global index. One
888 // could make that unique by doing a parallel scan at map
889 // construction time.
890
891 std::vector<GO> rowInds;
892 const GO lclMinGblRowInd = this->impl_.getMyGlobalRowIndices(rowInds);
893
894 // Compute the globally min row index for the "index base."
895 GO gblMinGblRowInd = 0; // output argument
898 const GO indexBase = gblMinGblRowInd;
899 const GST INV = Tpetra::Details::OrdinalTraits<GST>::invalid();
900 return rcp(new map_type(INV, rowInds.data(), rowInds.size(),
901 indexBase, comm));
902 }
903
904 protected:
908 virtual size_t constantNumberOfPackets() const {
909 return static_cast<size_t>(0);
910 }
911
915 virtual bool
916 checkSizes(const ::Tpetra::SrcDistObject& source) {
917 using std::endl;
919 const char prefix[] = "Tpetra::Details::CooMatrix::checkSizes: ";
920
921 const this_COO_type* src = dynamic_cast<const this_COO_type*>(&source);
922
923 if (src == NULL) {
924 std::ostream& err = markLocalErrorAndGetStream();
925 err << prefix << "The source object of the Import or Export "
926 "must be a CooMatrix with the same template parameters as the "
927 "target object."
928 << endl;
929 } else if (this->map_.is_null()) {
930 std::ostream& err = markLocalErrorAndGetStream();
931 err << prefix << "The target object of the Import or Export "
932 "must be a CooMatrix with a nonnull Map."
933 << endl;
934 }
935 return !(*(this->localError_));
936 }
937
940 typename ::Tpetra::DistObject<char, LO, GO, NT>::buffer_device_type;
941
942 virtual void
943 copyAndPermute(const ::Tpetra::SrcDistObject& sourceObject,
944 const size_t numSameIDs,
945 const Kokkos::DualView<const LO*,
947 const Kokkos::DualView<const LO*,
949 const CombineMode /* CM */) {
950 using std::endl;
952 const char prefix[] = "Tpetra::Details::CooMatrix::copyAndPermute: ";
953
954 // There's no communication in this method, so it's safe just to
955 // return on error.
956
957 if (*(this->localError_)) {
958 std::ostream& err = this->markLocalErrorAndGetStream();
959 err << prefix << "The target object of the Import or Export is "
960 "already in an error state."
961 << endl;
962 return;
963 }
964
965 const this_COO_type* src = dynamic_cast<const this_COO_type*>(&sourceObject);
966 if (src == nullptr) {
967 std::ostream& err = this->markLocalErrorAndGetStream();
968 err << prefix << "Input argument 'sourceObject' is not a CooMatrix."
969 << endl;
970 return;
971 }
972
973 const size_t numPermuteIDs =
974 static_cast<size_t>(permuteToLIDs.extent(0));
975 if (numPermuteIDs != static_cast<size_t>(permuteFromLIDs.extent(0))) {
976 std::ostream& err = this->markLocalErrorAndGetStream();
977 err << prefix << "permuteToLIDs.extent(0) = "
978 << numPermuteIDs << " != permuteFromLIDs.extent(0) = "
979 << permuteFromLIDs.extent(0) << "." << endl;
980 return;
981 }
982 if (sizeof(int) <= sizeof(size_t) &&
983 numPermuteIDs > static_cast<size_t>(std::numeric_limits<int>::max())) {
984 std::ostream& err = this->markLocalErrorAndGetStream();
985 err << prefix << "numPermuteIDs = " << numPermuteIDs
986 << ", a size_t, overflows int." << endl;
987 return;
988 }
989
990 // Even though this is an std::set, we can start with numSameIDs
991 // just by iterating through the first entries of the set.
992
993 if (sizeof(int) <= sizeof(size_t) &&
994 numSameIDs > static_cast<size_t>(std::numeric_limits<int>::max())) {
995 std::ostream& err = this->markLocalErrorAndGetStream();
996 err << prefix << "numSameIDs = " << numSameIDs
997 << ", a size_t, overflows int." << endl;
998 return;
999 }
1000
1001 //
1002 // Copy in entries from any initial rows with the same global row indices.
1003 //
1004 const LO numSame = static_cast<int>(numSameIDs);
1005 // Count of local row indices encountered here with invalid global
1006 // row indices. If nonzero, something went wrong. If something
1007 // did go wrong, we'll defer responding until the end of this
1008 // method, so we can print as much useful info as possible.
1009 LO numInvalidSameRows = 0;
1010 for (LO lclRow = 0; lclRow < numSame; ++lclRow) {
1011 // All numSame initial rows have the same global index in both
1012 // source and target Maps, so we only need to convert to global
1013 // once.
1014 const GO gblRow = this->map_->getGlobalElement(lclRow);
1015 if (gblRow == ::Tpetra::Details::OrdinalTraits<GO>::invalid()) {
1017 continue;
1018 } else {
1019 this->impl_.mergeIntoRow(gblRow, src->impl_, gblRow);
1020 }
1021 }
1022
1023 //
1024 // Copy in entries from remaining rows that are permutations, that
1025 // is, that live in both the source and target Maps, but aren't
1026 // included in the "same" list (see above).
1027 //
1028 const LO numPermute = static_cast<int>(numPermuteIDs);
1029 // Count of local "from" row indices encountered here with invalid
1030 // global row indices. If nonzero, something went wrong. If
1031 // something did go wrong, we'll defer responding until the end of
1032 // this method, so we can print as much useful info as possible.
1033 LO numInvalidRowsFrom = 0;
1034 // Count of local "to" row indices encountered here with invalid
1035 // global row indices. If nonzero, something went wrong. If
1036 // something did go wrong, we'll defer responding until the end of
1037 // this method, so we can print as much useful info as possible.
1038 LO numInvalidRowsTo = 0;
1039
1040 TEUCHOS_ASSERT(!permuteFromLIDs.need_sync_host());
1041 TEUCHOS_ASSERT(!permuteToLIDs.need_sync_host());
1042 auto permuteFromLIDs_h = permuteFromLIDs.view_host();
1043 auto permuteToLIDs_h = permuteToLIDs.view_host();
1044
1045 for (LO k = 0; k < numPermute; ++k) {
1046 const LO lclRowFrom = permuteFromLIDs_h[k];
1047 const LO lclRowTo = permuteToLIDs_h[k];
1048 const GO gblRowFrom = src->map_->getGlobalElement(lclRowFrom);
1049 const GO gblRowTo = this->map_->getGlobalElement(lclRowTo);
1050
1051 bool bothConversionsValid = true;
1052 if (gblRowFrom == ::Tpetra::Details::OrdinalTraits<GO>::invalid()) {
1054 bothConversionsValid = false;
1055 }
1056 if (gblRowTo == ::Tpetra::Details::OrdinalTraits<GO>::invalid()) {
1058 bothConversionsValid = false;
1059 }
1061 this->impl_.mergeIntoRow(gblRowTo, src->impl_, gblRowFrom);
1062 }
1063 }
1064
1065 // Print info if any errors occurred.
1066 if (numInvalidSameRows != 0 || numInvalidRowsFrom != 0 ||
1067 numInvalidRowsTo != 0) {
1068 // Collect and print all the invalid input row indices, for the
1069 // "same," "from," and "to" lists.
1070 std::vector<std::pair<LO, GO> > invalidSameRows;
1072 std::vector<std::pair<LO, GO> > invalidRowsFrom;
1074 std::vector<std::pair<LO, GO> > invalidRowsTo;
1076
1077 for (LO lclRow = 0; lclRow < numSame; ++lclRow) {
1078 // All numSame initial rows have the same global index in both
1079 // source and target Maps, so we only need to convert to global
1080 // once.
1081 const GO gblRow = this->map_->getGlobalElement(lclRow);
1082 if (gblRow == ::Tpetra::Details::OrdinalTraits<GO>::invalid()) {
1083 invalidSameRows.push_back({lclRow, gblRow});
1084 }
1085 }
1086
1087 for (LO k = 0; k < numPermute; ++k) {
1088 const LO lclRowFrom = permuteFromLIDs_h[k];
1089 const LO lclRowTo = permuteToLIDs_h[k];
1090 const GO gblRowFrom = src->map_->getGlobalElement(lclRowFrom);
1091 const GO gblRowTo = this->map_->getGlobalElement(lclRowTo);
1092
1093 if (gblRowFrom == ::Tpetra::Details::OrdinalTraits<GO>::invalid()) {
1095 }
1096 if (gblRowTo == ::Tpetra::Details::OrdinalTraits<GO>::invalid()) {
1097 invalidRowsTo.push_back({lclRowTo, gblRowTo});
1098 }
1099 }
1100
1101 std::ostringstream os;
1102 if (numInvalidSameRows != 0) {
1103 os << "Invalid permute \"same\" (local, global) index pairs: [";
1104 for (std::size_t k = 0; k < invalidSameRows.size(); ++k) {
1105 const auto& p = invalidSameRows[k];
1106 os << "(" << p.first << "," << p.second << ")";
1107 if (k + 1 < invalidSameRows.size()) {
1108 os << ", ";
1109 }
1110 }
1111 os << "]" << std::endl;
1112 }
1113 if (numInvalidRowsFrom != 0) {
1114 os << "Invalid permute \"from\" (local, global) index pairs: [";
1115 for (std::size_t k = 0; k < invalidRowsFrom.size(); ++k) {
1116 const auto& p = invalidRowsFrom[k];
1117 os << "(" << p.first << "," << p.second << ")";
1118 if (k + 1 < invalidRowsFrom.size()) {
1119 os << ", ";
1120 }
1121 }
1122 os << "]" << std::endl;
1123 }
1124 if (numInvalidRowsTo != 0) {
1125 os << "Invalid permute \"to\" (local, global) index pairs: [";
1126 for (std::size_t k = 0; k < invalidRowsTo.size(); ++k) {
1127 const auto& p = invalidRowsTo[k];
1128 os << "(" << p.first << "," << p.second << ")";
1129 if (k + 1 < invalidRowsTo.size()) {
1130 os << ", ";
1131 }
1132 }
1133 os << "]" << std::endl;
1134 }
1135
1136 std::ostream& err = this->markLocalErrorAndGetStream();
1137 err << prefix << os.str();
1138 return;
1139 }
1140 }
1141
1142 virtual void
1143 packAndPrepare(const ::Tpetra::SrcDistObject& sourceObject,
1144 const Kokkos::DualView<const local_ordinal_type*,
1146 Kokkos::DualView<packet_type*,
1147 buffer_device_type>& exports,
1148 Kokkos::DualView<size_t*,
1151 size_t& constantNumPackets) {
1152 using std::endl;
1153 using Teuchos::Comm;
1154 using Teuchos::RCP;
1156 const char prefix[] = "Tpetra::Details::CooMatrix::packAndPrepare: ";
1157 const char suffix[] =
1158 " This should never happen. "
1159 "Please report this bug to the Tpetra developers.";
1160
1161 // Tell the caller that different rows may have different numbers
1162 // of matrix entries.
1164
1165 const this_COO_type* src = dynamic_cast<const this_COO_type*>(&sourceObject);
1166 if (src == nullptr) {
1167 std::ostream& err = this->markLocalErrorAndGetStream();
1168 err << prefix << "Input argument 'sourceObject' is not a CooMatrix."
1169 << endl;
1170 } else if (*(src->localError_)) {
1171 std::ostream& err = this->markLocalErrorAndGetStream();
1172 err << prefix << "The source (input) object of the Import or Export "
1173 "is already in an error state on this process."
1174 << endl;
1175 } else if (*(this->localError_)) {
1176 std::ostream& err = this->markLocalErrorAndGetStream();
1177 err << prefix << "The target (output, \"this\") object of the Import "
1178 "or Export is already in an error state on this process."
1179 << endl;
1180 }
1181 // Respond to detected error(s) by resizing 'exports' to zero (so
1182 // we won't be tempted to read it later), and filling
1183 // numPacketsPerLID with zeros.
1184 if (*(this->localError_)) {
1185 // Resize 'exports' to zero, so we won't be tempted to read it.
1186 Details::reallocDualViewIfNeeded(exports, 0, "CooMatrix exports");
1187 // Trick to get around const DualView& being const.
1188 {
1189 auto numPacketsPerLID_tmp = numPacketsPerLID;
1190 numPacketsPerLID_tmp.sync_host();
1191 numPacketsPerLID_tmp.modify_host();
1192 }
1193 // Fill numPacketsPerLID with zeros.
1194 Kokkos::deep_copy(numPacketsPerLID.view_host(), static_cast<size_t>(0));
1195 return;
1196 }
1197
1198 const size_t numExports = exportLIDs.extent(0);
1199 if (numExports == 0) {
1200 Details::reallocDualViewIfNeeded(exports, 0, exports.view_host().label());
1201 return; // nothing to send
1202 }
1203 RCP<const Comm<int> > comm = src->getMap().is_null() ? Teuchos::null : src->getMap()->getComm();
1204 if (comm.is_null() || comm->getSize() == 1) {
1205 if (numExports != static_cast<size_t>(0)) {
1206 std::ostream& err = this->markLocalErrorAndGetStream();
1207 err << prefix << "The input communicator is either null or "
1208 "has only one process, but numExports = "
1209 << numExports << " != 0."
1210 << suffix << endl;
1211 return;
1212 }
1213 // Don't go into the rest of this method unless there are
1214 // actually processes other than the calling process. This is
1215 // because the pack and unpack functions only have nonstub
1216 // implementations if building with MPI.
1217 return;
1218 }
1219
1220 numPacketsPerLID.sync_host();
1221 numPacketsPerLID.modify_host();
1222
1223 TEUCHOS_ASSERT(!exportLIDs.need_sync_host());
1224 auto exportLIDs_h = exportLIDs.view_host();
1225
1226 int totalNumPackets = 0;
1227 size_t numInvalidRowInds = 0;
1228 std::ostringstream errStrm; // current loop iteration's error messages
1229 for (size_t k = 0; k < numExports; ++k) {
1230 const LO lclRow = exportLIDs_h[k];
1231 // We're packing the source object's data, so we need to use the
1232 // source object's Map to convert from local to global indices.
1233 const GO gblRow = src->map_->getGlobalElement(lclRow);
1234 if (gblRow == ::Tpetra::Details::OrdinalTraits<GO>::invalid()) {
1235 // Mark the error later; just count for now.
1236 ++numInvalidRowInds;
1237 numPacketsPerLID.view_host()[k] = 0;
1238 continue;
1239 }
1240
1241 // Count the number of bytes needed to pack the current row of
1242 // the source object.
1243 int numPackets = 0;
1244 const int errCode =
1245 src->impl_.countPackRow(numPackets, gblRow, *comm, &errStrm);
1246 if (errCode != 0) {
1247 std::ostream& err = this->markLocalErrorAndGetStream();
1248 err << prefix << errStrm.str() << endl;
1249 numPacketsPerLID.view_host()[k] = 0;
1250 continue;
1251 }
1252
1253 // Make sure that the total number of packets fits in int.
1254 // MPI requires this.
1255 const long long newTotalNumPackets =
1256 static_cast<long long>(totalNumPackets) +
1257 static_cast<long long>(numPackets);
1258 if (newTotalNumPackets >
1259 static_cast<long long>(std::numeric_limits<int>::max())) {
1260 std::ostream& err = this->markLocalErrorAndGetStream();
1261 err << prefix << "The new total number of packets "
1262 << newTotalNumPackets << " does not fit in int." << endl;
1263 // At this point, we definitely cannot continue. In order to
1264 // leave the output arguments in a rational state, we zero out
1265 // all remaining entries of numPacketsPerLID before returning.
1266 for (size_t k2 = k; k2 < numExports; ++k2) {
1267 numPacketsPerLID.view_host()[k2] = 0;
1268 }
1269 return;
1270 }
1271 numPacketsPerLID.view_host()[k] = static_cast<size_t>(numPackets);
1272 totalNumPackets = static_cast<int>(newTotalNumPackets);
1273 }
1274
1275 // If we found invalid row indices in exportLIDs, go back,
1276 // collect, and report them.
1277 if (numInvalidRowInds != 0) {
1278 std::vector<std::pair<LO, GO> > invalidRowInds;
1279 for (size_t k = 0; k < numExports; ++k) {
1280 const LO lclRow = exportLIDs_h[k];
1281 // We're packing the source object's data, so we need to use
1282 // the source object's Map to convert from local to global
1283 // indices.
1284 const GO gblRow = src->map_->getGlobalElement(lclRow);
1285 if (gblRow == ::Tpetra::Details::OrdinalTraits<GO>::invalid()) {
1286 invalidRowInds.push_back({lclRow, gblRow});
1287 }
1288 }
1289 std::ostringstream os;
1290 os << prefix << "We found " << numInvalidRowInds << " invalid row ind"
1291 << (numInvalidRowInds != static_cast<size_t>(1) ? "ices" : "ex")
1292 << " out of " << numExports << " in exportLIDs. Here is the list "
1293 << " of invalid row indices: [";
1294 for (size_t k = 0; k < invalidRowInds.size(); ++k) {
1295 os << "(LID: " << invalidRowInds[k].first << ", GID: "
1296 << invalidRowInds[k].second << ")";
1297 if (k + 1 < invalidRowInds.size()) {
1298 os << ", ";
1299 }
1300 }
1301 os << "].";
1302
1303 std::ostream& err = this->markLocalErrorAndGetStream();
1304 err << prefix << os.str() << std::endl;
1305 return;
1306 }
1307
1308 {
1309 const bool reallocated =
1310 Details::reallocDualViewIfNeeded(exports, totalNumPackets,
1311 "CooMatrix exports");
1312 if (reallocated) {
1313 exports.sync_host(); // make sure alloc'd on host
1314 }
1315 }
1316 exports.modify_host();
1317
1318 // FIXME (mfh 17 Jan 2017) packTriples wants three arrays, not a
1319 // single array of structs. For now, we just copy.
1320 std::vector<GO> gblRowInds;
1321 std::vector<GO> gblColInds;
1322 std::vector<SC> vals;
1323
1324 int outBufCurPos = 0;
1325 packet_type* outBuf = exports.view_host().data();
1326 for (size_t k = 0; k < numExports; ++k) {
1327 const LO lclRow = exportLIDs.view_host()[k];
1328 // We're packing the source object's data, so we need to use the
1329 // source object's Map to convert from local to global indices.
1330 const GO gblRow = src->map_->getGlobalElement(lclRow);
1331 // Pack the current row of the source object.
1332 src->impl_.packRow(outBuf, totalNumPackets, outBufCurPos, *comm,
1333 gblRowInds, gblColInds, vals, gblRow);
1334 }
1335 }
1336
1337 virtual void
1338 unpackAndCombine(const Kokkos::DualView<const local_ordinal_type*,
1339 buffer_device_type>& importLIDs,
1340 Kokkos::DualView<packet_type*,
1342 imports,
1343 Kokkos::DualView<size_t*,
1345 numPacketsPerLID,
1346 const size_t /* constantNumPackets */,
1347 const ::Tpetra::CombineMode /* combineMode */) {
1348 using std::endl;
1349 using Teuchos::Comm;
1350 using Teuchos::RCP;
1351 const char prefix[] = "Tpetra::Details::CooMatrix::unpackAndCombine: ";
1352 const char suffix[] =
1353 " This should never happen. "
1354 "Please report this bug to the Tpetra developers.";
1355
1356 TEUCHOS_ASSERT(!importLIDs.need_sync_host());
1357 auto importLIDs_h = importLIDs.view_host();
1358
1359 const std::size_t numImports = importLIDs.extent(0);
1360 if (numImports == 0) {
1361 return; // nothing to receive
1362 } else if (imports.extent(0) == 0) {
1363 std::ostream& err = this->markLocalErrorAndGetStream();
1364 err << prefix << "importLIDs.extent(0) = " << numImports << " != 0, "
1365 << "but imports.extent(0) = 0. This doesn't make sense, because "
1366 << "for every incoming LID, CooMatrix packs at least the count of "
1367 << "triples associated with that LID, even if the count is zero. "
1368 << "importLIDs = [";
1369 for (std::size_t k = 0; k < numImports; ++k) {
1370 err << importLIDs_h[k];
1371 if (k + 1 < numImports) {
1372 err << ", ";
1373 }
1374 }
1375 err << "]. " << suffix << endl;
1376 return;
1377 }
1378
1379 RCP<const Comm<int> > comm = this->getMap().is_null() ? Teuchos::null : this->getMap()->getComm();
1380 if (comm.is_null() || comm->getSize() == 1) {
1381 if (numImports != static_cast<size_t>(0)) {
1382 std::ostream& err = this->markLocalErrorAndGetStream();
1383 err << prefix << "The input communicator is either null or "
1384 "has only one process, but numImports = "
1385 << numImports << " != 0."
1386 << suffix << endl;
1387 return;
1388 }
1389 // Don't go into the rest of this method unless there are
1390 // actually processes other than the calling process. This is
1391 // because the pack and unpack functions only have nonstub
1392 // implementations if building with MPI.
1393 return;
1394 }
1395
1396 // Make sure that the length of 'imports' fits in int.
1397 // This is ultimately an MPI restriction.
1398 if (static_cast<size_t>(imports.extent(0)) >
1399 static_cast<size_t>(std::numeric_limits<int>::max())) {
1400 std::ostream& err = this->markLocalErrorAndGetStream();
1401 err << prefix << "imports.extent(0) = "
1402 << imports.extent(0) << " does not fit in int." << endl;
1403 return;
1404 }
1405 const int inBufSize = static_cast<int>(imports.extent(0));
1406
1407 if (imports.need_sync_host()) {
1408 imports.sync_host();
1409 }
1410 if (numPacketsPerLID.need_sync_host()) {
1411 numPacketsPerLID.sync_host();
1412 }
1413 auto imports_h = imports.view_host();
1414 auto numPacketsPerLID_h = numPacketsPerLID.view_host();
1415
1416 // FIXME (mfh 17,24 Jan 2017) packTriples wants three arrays, not a
1417 // single array of structs. For now, we just copy.
1418 std::vector<GO> gblRowInds;
1419 std::vector<GO> gblColInds;
1420 std::vector<SC> vals;
1421
1422 const packet_type* inBuf = imports_h.data();
1423 int inBufCurPos = 0;
1424 size_t numInvalidRowInds = 0;
1425 int errCode = 0;
1426 std::ostringstream errStrm; // for unpack* error output.
1427 for (size_t k = 0; k < numImports; ++k) {
1428 const LO lclRow = importLIDs_h(k);
1429 const GO gblRow = this->map_->getGlobalElement(lclRow);
1430 if (gblRow == ::Tpetra::Details::OrdinalTraits<GO>::invalid()) {
1431 ++numInvalidRowInds;
1432 continue;
1433 }
1434
1435 // Remember where we were, so we don't overrun the buffer
1436 // length. inBufCurPos is an in/out argument of unpackTriples*.
1437 const int origInBufCurPos = inBufCurPos;
1438
1439 int numEnt = 0; // output argument of unpackTriplesCount
1440 errCode = unpackTriplesCount(inBuf, inBufSize, inBufCurPos,
1441 numEnt, *comm, &errStrm);
1442 if (errCode != 0 || numEnt < 0 || inBufCurPos < origInBufCurPos) {
1443 std::ostream& err = this->markLocalErrorAndGetStream();
1444
1445 err << prefix << "In unpack loop, k=" << k << ": ";
1446 if (errCode != 0) {
1447 err << " unpackTriplesCount returned errCode = " << errCode
1448 << " != 0." << endl;
1449 }
1450 if (numEnt < 0) {
1451 err << " unpackTriplesCount returned errCode = 0, but numEnt = "
1452 << numEnt << " < 0." << endl;
1453 }
1454 if (inBufCurPos < origInBufCurPos) {
1455 err << " After unpackTriplesCount, inBufCurPos = " << inBufCurPos
1456 << " < origInBufCurPos = " << origInBufCurPos << "." << endl;
1457 }
1458 err << " unpackTriplesCount report: " << errStrm.str() << endl;
1459 err << suffix << endl;
1460
1461 // We only continue in a debug build, because the above error
1462 // messages could consume too much memory and cause an
1463 // out-of-memory error, without actually printing. Printing
1464 // everything is useful in a debug build, but not so much in a
1465 // release build.
1466#ifdef HAVE_TPETRA_DEBUG
1467 // Clear out the current error stream, so we don't accumulate
1468 // over loop iterations.
1469 errStrm.str("");
1470 continue;
1471#else
1472 return;
1473#endif // HAVE_TPETRA_DEBUG
1474 }
1475
1476 // FIXME (mfh 17,24 Jan 2017) packTriples wants three arrays,
1477 // not a single array of structs. For now, we just copy.
1478 gblRowInds.resize(numEnt);
1479 gblColInds.resize(numEnt);
1480 vals.resize(numEnt);
1481
1482 errCode = unpackTriples(inBuf, inBufSize, inBufCurPos,
1483 gblRowInds.data(), gblColInds.data(),
1484 vals.data(), numEnt, *comm, &errStrm);
1485 if (errCode != 0) {
1486 std::ostream& err = this->markLocalErrorAndGetStream();
1487 err << prefix << "unpackTriples returned errCode = "
1488 << errCode << " != 0. It reports: " << errStrm.str()
1489 << endl;
1490 // We only continue in a debug build, because the above error
1491 // messages could consume too much memory and cause an
1492 // out-of-memory error, without actually printing. Printing
1493 // everything is useful in a debug build, but not so much in a
1494 // release build.
1495#ifdef HAVE_TPETRA_DEBUG
1496 // Clear out the current error stream, so we don't accumulate
1497 // over loop iterations.
1498 errStrm.str("");
1499 continue;
1500#else
1501 return;
1502#endif // HAVE_TPETRA_DEBUG
1503 }
1504 this->sumIntoGlobalValues(gblRowInds.data(), gblColInds.data(),
1505 vals.data(), numEnt);
1506 }
1507
1508 // If we found invalid row indices in exportLIDs, go back,
1509 // collect, and report them.
1510 if (numInvalidRowInds != 0) {
1511 // Mark the error now, before we possibly run out of memory.
1512 // The latter could raise an exception (e.g., std::bad_alloc),
1513 // but at least we would get the error state right.
1514 std::ostream& err = this->markLocalErrorAndGetStream();
1515
1516 std::vector<std::pair<LO, GO> > invalidRowInds;
1517 for (size_t k = 0; k < numImports; ++k) {
1518 const LO lclRow = importLIDs_h(k);
1519 const GO gblRow = this->map_->getGlobalElement(lclRow);
1520 if (gblRow == ::Tpetra::Details::OrdinalTraits<GO>::invalid()) {
1521 invalidRowInds.push_back({lclRow, gblRow});
1522 }
1523 }
1524
1525 err << prefix << "We found " << numInvalidRowInds << " invalid row ind"
1526 << (numInvalidRowInds != static_cast<size_t>(1) ? "ices" : "ex")
1527 << " out of " << numImports << " in importLIDs. Here is the list "
1528 << " of invalid row indices: [";
1529 for (size_t k = 0; k < invalidRowInds.size(); ++k) {
1530 err << "(LID: " << invalidRowInds[k].first << ", GID: "
1531 << invalidRowInds[k].second << ")";
1532 if (k + 1 < invalidRowInds.size()) {
1533 err << ", ";
1534 }
1535 }
1536 err << "].";
1537 return;
1538 }
1539 }
1540};
1541
1542} // namespace Details
1543} // namespace Tpetra
1544
1545#endif // TPETRA_DETAILS_COOMATRIX_HPP
Declaration of a function that prints strings from each process.
Declaration and definition of Tpetra::Details::reallocDualViewIfNeeded, an implementation detail of T...
Struct that holds views of the contents of a CrsMatrix.
Sparse matrix used only for file input / output.
void sumIntoGlobalValues(const GO gblRowInds[], const GO gblColInds[], const SC vals[], const std::size_t numEnt)
Insert multiple entries locally into the sparse matrix.
virtual std::string description() const
One-line descriptiion of this object; overrides Teuchos::Describable method.
virtual size_t constantNumberOfPackets() const
By returning 0, tell DistObject that this class may not necessarily have a constant number of "packet...
virtual ~CooMatrix()
Destructor (virtual for memory safety of derived classes).
void fillComplete()
Special version of fillComplete that assumes that the matrix already has a Map, and reuses its commun...
typename ::Tpetra::DistObject< char, LO, GO, NT >::buffer_device_type buffer_device_type
Kokkos::Device specialization for DistObject communication buffers.
SC scalar_type
Type of each entry (value) in the sparse matrix.
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).
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...
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,...
CooMatrix(const ::Teuchos::RCP< const map_type > &map)
Constructor that takes a Map.
bool localError() const
Whether this object had an error on the calling process.
virtual bool checkSizes(const ::Tpetra::SrcDistObject &source)
Compare the source and target (this) objects for compatibility.
std::size_t getLclNumEntries() const
Number of entries in the sparse matrix on the calling process.
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...
std::string errorMessages() const
The current stream of error messages.
char packet_type
This class transfers data as bytes (MPI_BYTE).
::Tpetra::Map< local_ordinal_type, global_ordinal_type, node_type > map_type
Type of the Map specialization to give to the constructor.
Implementation detail of Tpetra::Details::CooMatrix (which see below).
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,...
std::size_t getLclNumEntries() const
Number of entries in the sparse matrix on the calling process.
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.
void sumIntoGlobalValues(const GO gblRowInds[], const GO gblColInds[], const SC vals[], const std::size_t numEnt)
Insert multiple entries locally into the sparse matrix.
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.
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)...
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...
char packet_type
Type for packing and unpacking data.
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.
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.
CooMatrixImpl()=default
Default constructor.
Base class for distributed Tpetra objects that support data redistribution.
Teuchos::RCP< const map_type > map_
The Map over which this object is distributed.
Node node_type
The Node type. If you don't know what this is, don't use it.
virtual Teuchos::RCP< const map_type > getMap() const
The Map describing the parallel distribution of this object.
Implementation details of Tpetra.
int packTriplesCount(const int, char[], const int, int &, const ::Teuchos::Comm< int > &, std::ostream *errStrm)
Pack the count (number) of matrix triples.
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").
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.
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.
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.
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.
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,...
Namespace Tpetra contains the class and methods constituting the Tpetra library.
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.
CombineMode
Rule for combining data in an Import or Export.
Function comparing two CooGraphEntry structs, lexicographically, first by row index,...
Type of each (row index, column index) pair in the Tpetra::Details::CooMatrix (see below).