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
216 const GO gblRow,
217 const ::Teuchos::Comm<int>& comm,
218 std::ostream* errStrm = NULL) const {
219 using std::endl;
220 using ::Tpetra::Details::countPackTriples;
221 using ::Tpetra::Details::countPackTriplesCount;
222 const char prefix[] = "Tpetra::Details::Impl::CooMatrixImpl::countPackRow: ";
223#ifdef HAVE_TPETRACORE_MPI
224 int errCode = MPI_SUCCESS;
225#else
226 int errCode = 0;
227#endif // HAVE_TPETRACORE_MPI
228
229 // Count the number of entries in the given row.
230 const GO minGO = std::numeric_limits<GO>::min();
231 auto beg = this->entries_.lower_bound({gblRow, minGO});
232 auto end = this->entries_.upper_bound({gblRow + 1, minGO});
233 int numEnt = 0;
234 for (auto iter = beg; iter != end; ++iter) {
235 ++numEnt;
236 if (numEnt == std::numeric_limits<int>::max()) {
237 if (errStrm != NULL) {
238 *errStrm << prefix << "In (global) row " << gblRow << ", the number "
239 "of entries thus far, numEnt = "
240 << numEnt << ", has reached the "
241 "maximum int value. We need to store this count as int for MPI's "
242 "sake."
243 << endl;
244 }
245 return -1;
246 }
247 }
248
249 int numPacketsForCount = 0; // output argument of countPackTriplesCount
250 {
251 errCode =
253 if (errCode != 0) {
254 if (errStrm != NULL) {
255 *errStrm << prefix << "countPackTriplesCount "
256 "returned errCode = "
257 << errCode << " != 0." << endl;
258 }
259 return errCode;
260 }
261 if (numPacketsForCount < 0) {
262 if (errStrm != NULL) {
263 *errStrm << prefix << "countPackTriplesCount returned "
264 "numPacketsForCount = "
265 << numPacketsForCount << " < 0." << endl;
266 }
267 return -1;
268 }
269 }
270
271 int numPacketsForTriples = 0; // output argument of countPackTriples
272 {
274 TEUCHOS_TEST_FOR_EXCEPTION(errCode != 0, std::runtime_error, prefix << "countPackTriples "
275 "returned errCode = "
276 << errCode << " != 0.");
277 TEUCHOS_TEST_FOR_EXCEPTION(numPacketsForTriples < 0, std::logic_error, prefix << "countPackTriples "
278 "returned numPacketsForTriples = "
279 << numPacketsForTriples << " < 0.");
280 }
281
283 return errCode;
284 }
285
300 void
302 const int outBufSize,
303 int& outBufCurPos, // in/out argument
304 const ::Teuchos::Comm<int>& comm,
305 std::vector<GO>& gblRowInds,
306 std::vector<GO>& gblColInds,
307 std::vector<SC>& vals,
308 const GO gblRow) const {
309 using ::Tpetra::Details::packTriples;
310 using ::Tpetra::Details::packTriplesCount;
311 const char prefix[] = "Tpetra::Details::Impl::CooMatrixImpl::packRow: ";
312
313 const GO minGO = std::numeric_limits<GO>::min();
314 auto beg = this->entries_.lower_bound({gblRow, minGO});
315 auto end = this->entries_.upper_bound({gblRow + 1, minGO});
316
317 // This doesn't actually deallocate. Only swapping with an empty
318 // std::vector does that.
319 gblRowInds.resize(0);
320 gblColInds.resize(0);
321 vals.resize(0);
322
323 int numEnt = 0;
324 for (auto iter = beg; iter != end; ++iter) {
325 gblRowInds.push_back(iter->first.row);
326 gblColInds.push_back(iter->first.col);
327 vals.push_back(iter->second);
328 ++numEnt;
329 TEUCHOS_TEST_FOR_EXCEPTION(numEnt == std::numeric_limits<int>::max(), std::runtime_error, prefix << "In (global) row " << gblRow << ", the number of entries thus far, "
330 "numEnt = "
331 << numEnt << ", has reached the maximum int value. "
332 "We need to store this count as int for MPI's sake.");
333 }
334
335 {
336 const int errCode =
338 TEUCHOS_TEST_FOR_EXCEPTION(errCode != 0, std::runtime_error, prefix << "In (global) row " << gblRow << ", packTriplesCount returned "
339 "errCode = "
340 << errCode << " != 0.");
341 }
342 {
343 const int errCode =
344 packTriples(gblRowInds.data(),
345 gblColInds.data(),
346 vals.data(),
347 numEnt,
348 outBuf,
350 outBufCurPos, // in/out argument
351 comm);
352 TEUCHOS_TEST_FOR_EXCEPTION(errCode != 0, std::runtime_error, prefix << "In (global) row " << gblRow << ", packTriples returned errCode = " << errCode << " != 0.");
353 }
354 }
355
363 GO getMyGlobalRowIndices(std::vector<GO>& rowInds) const {
364 rowInds.clear();
365
366 GO lclMinRowInd = std::numeric_limits<GO>::max(); // compute local min
367 for (typename entries_type::const_iterator iter = this->entries_.begin();
368 iter != this->entries_.end(); ++iter) {
369 const GO rowInd = iter->first.row;
370 if (rowInd < lclMinRowInd) {
372 }
373 if (rowInds.empty() || rowInds.back() != rowInd) {
374 rowInds.push_back(rowInd); // don't insert duplicates
375 }
376 }
377 return lclMinRowInd;
378 }
379
380 template <class OffsetType>
381 void
382 buildCrs(std::vector<OffsetType>& rowOffsets,
383 GO gblColInds[],
384 SC vals[]) const {
385 static_assert(std::is_integral<OffsetType>::value,
386 "OffsetType must be a built-in integer type.");
387
388 // clear() doesn't generally free storage; it just resets the
389 // length. Thus, we reuse any existing storage here.
390 rowOffsets.clear();
391
392 const std::size_t numEnt = this->getLclNumEntries();
393 if (numEnt == 0) {
394 rowOffsets.push_back(0);
395 } else {
396 typename entries_type::const_iterator iter = this->entries_.begin();
397 GO prevGblRowInd = iter->first.row;
398
399 OffsetType k = 0;
400 for (; iter != this->entries_.end(); ++iter, ++k) {
401 const GO gblRowInd = iter->first.row;
402 if (k == 0 || gblRowInd != prevGblRowInd) {
403 // The row offsets array always has at least one entry. The
404 // first entry is always zero, and the last entry is always
405 // the number of matrix entries.
406 rowOffsets.push_back(k);
408 }
409 gblColInds[k] = iter->first.col;
410
411 static_assert(std::is_same<typename std::decay<decltype(iter->second)>::type, SC>::value,
412 "The type of iter->second != SC.");
413 vals[k] = iter->second;
414 }
415 rowOffsets.push_back(static_cast<OffsetType>(numEnt));
416 }
417 }
418
431 template <class OffsetType, class LO>
432 void
433 buildLocallyIndexedCrs(std::vector<OffsetType>& rowOffsets,
434 LO lclColInds[],
435 SC vals[],
436 std::function<LO(const GO)> gblToLcl) const {
437 static_assert(std::is_integral<OffsetType>::value,
438 "OffsetType must be a built-in integer type.");
439 static_assert(std::is_integral<LO>::value,
440 "LO must be a built-in integer type.");
441
442 // clear() doesn't generally free storage; it just resets the
443 // length. Thus, we reuse any existing storage here.
444 rowOffsets.clear();
445
446 const std::size_t numEnt = this->getLclNumEntries();
447 if (numEnt == 0) {
448 rowOffsets.push_back(0);
449 } else {
450 typename entries_type::const_iterator iter = this->entries_.begin();
451 GO prevGblRowInd = iter->first.row;
452
453 OffsetType k = 0;
454 for (; iter != this->entries_.end(); ++iter, ++k) {
455 const GO gblRowInd = iter->first.row;
456 if (k == 0 || gblRowInd != prevGblRowInd) {
457 // The row offsets array always has at least one entry. The
458 // first entry is always zero, and the last entry is always
459 // the number of matrix entries.
460 rowOffsets.push_back(k);
462 }
463 lclColInds[k] = gblToLcl(iter->first.col);
464 vals[k] = iter->second;
465 }
466 rowOffsets.push_back(static_cast<OffsetType>(numEnt));
467 }
468 }
469};
470
471} // namespace Impl
472
521template <class SC,
525class CooMatrix : public ::Tpetra::DistObject<char, LO, GO, NT> {
526 public:
528 typedef char packet_type;
531 typedef LO local_ordinal_type;
532 typedef GO global_ordinal_type;
533 typedef NT node_type;
534 typedef typename NT::device_type device_type;
536 typedef ::Tpetra::Map<local_ordinal_type, global_ordinal_type, node_type> map_type;
537
538 private:
540 typedef ::Tpetra::DistObject<packet_type, local_ordinal_type,
541 global_ordinal_type, node_type>
542 base_type;
543
546
547 public:
554 : base_type(::Teuchos::null)
555 , localError_(new bool(false))
556 , errs_(new std::shared_ptr<std::ostringstream>()) // ptr to a null ptr
557 {}
558
566 CooMatrix(const ::Teuchos::RCP<const map_type>& map)
567 : base_type(map)
568 , localError_(new bool(false))
569 , errs_(new std::shared_ptr<std::ostringstream>()) // ptr to a null ptr
570 {}
571
573 virtual ~CooMatrix() {}
574
581 void
583 const GO gblColInd,
584 const SC& val) {
586 }
587
596 void
598 const GO gblColInds[],
599 const SC vals[],
600 const std::size_t numEnt) {
602 }
603
605 void
606 sumIntoGlobalValues(std::initializer_list<GO> gblRowInds,
607 std::initializer_list<GO> gblColInds,
608 std::initializer_list<SC> vals,
609 const std::size_t numEnt) {
610 this->impl_.sumIntoGlobalValues(gblRowInds.begin(), gblColInds.begin(),
611 vals.begin(), numEnt);
612 }
613
615 std::size_t
617 return this->impl_.getLclNumEntries();
618 }
619
620 template <class OffsetType>
621 void
622 buildCrs(::Kokkos::View<OffsetType*, device_type>& rowOffsets,
623 ::Kokkos::View<GO*, device_type>& gblColInds,
624 ::Kokkos::View<typename ::KokkosKernels::ArithTraits<SC>::val_type*, device_type>& vals) {
625 static_assert(std::is_integral<OffsetType>::value,
626 "OffsetType must be a built-in integer type.");
627 using ::Kokkos::create_mirror_view;
628 using ::Kokkos::deep_copy;
629 using ::Kokkos::View;
630 typedef typename ::KokkosKernels::ArithTraits<SC>::val_type ISC;
631
632 const std::size_t numEnt = this->getLclNumEntries();
633
634 gblColInds = View<GO*, device_type>("gblColInds", numEnt);
636 auto gblColInds_h = create_mirror_view(gblColInds);
637 auto vals_h = create_mirror_view(vals);
638
639 std::vector<std::size_t> rowOffsetsSV;
640 this->impl_.buildCrs(rowOffsetsSV,
641 gblColInds_h.data(),
642 vals_h.data());
643 rowOffsets =
644 View<OffsetType*, device_type>("rowOffsets", rowOffsetsSV.size());
646 rowOffsets_h(rowOffsetsSV.data(), rowOffsetsSV.size());
648
651 }
652
663 void
664 fillComplete(const ::Teuchos::RCP<const ::Teuchos::Comm<int> >& comm) {
665 if (comm.is_null()) {
666 this->map_ = ::Teuchos::null;
667 } else {
668 this->map_ = this->buildMap(comm);
669 }
670 }
671
680 void
682 TEUCHOS_TEST_FOR_EXCEPTION(this->getMap().is_null(), std::runtime_error,
683 "Tpetra::Details::"
684 "CooMatrix::fillComplete: This object does not yet have a Map. "
685 "You must call the version of fillComplete "
686 "that takes an input communicator.");
687 this->fillComplete(this->getMap()->getComm());
688 }
689
704 bool localError() const {
705 return *localError_;
706 }
707
725 std::string errorMessages() const {
726 return ((*errs_).get() == NULL) ? std::string("") : (*errs_)->str();
727 }
728
729 private:
742 std::shared_ptr<bool> localError_;
743
751 std::shared_ptr<std::shared_ptr<std::ostringstream> > errs_;
752
754 std::ostream&
755 markLocalErrorAndGetStream() {
756 *(this->localError_) = true;
757 if ((*errs_).get() == NULL) {
758 *errs_ = std::shared_ptr<std::ostringstream>(new std::ostringstream());
759 }
760 return **errs_;
761 }
762
763 public:
766 virtual std::string description() const {
767 using Teuchos::TypeNameTraits;
768
769 std::ostringstream os;
770 os << "\"Tpetra::Details::CooMatrix\": {"
771 << "SC: " << TypeNameTraits<SC>::name()
772 << ", LO: " << TypeNameTraits<LO>::name()
773 << ", GO: " << TypeNameTraits<GO>::name()
774 << ", NT: " << TypeNameTraits<NT>::name();
775 if (this->getObjectLabel() != "") {
776 os << ", Label: \"" << this->getObjectLabel() << "\"";
777 }
778 os << ", Has Map: " << (this->map_.is_null() ? "false" : "true")
779 << "}";
780 return os.str();
781 }
782
785 virtual void
786 describe(Teuchos::FancyOStream& out,
787 const Teuchos::EVerbosityLevel verbLevel =
788 Teuchos::Describable::verbLevel_default) const {
789 using std::endl;
790 using ::Teuchos::EVerbosityLevel;
791 using ::Teuchos::OSTab;
792 using ::Teuchos::TypeNameTraits;
793 using ::Teuchos::VERB_DEFAULT;
794 using ::Teuchos::VERB_LOW;
795 using ::Teuchos::VERB_MEDIUM;
796 using ::Tpetra::Details::gathervPrint;
797
798 const auto vl = (verbLevel == VERB_DEFAULT) ? VERB_LOW : verbLevel;
799
800 auto comm = this->getMap().is_null() ? Teuchos::null : this->getMap()->getComm();
801 const int myRank = comm.is_null() ? 0 : comm->getRank();
802 // const int numProcs = comm.is_null () ? 1 : comm->getSize ();
803
804 if (vl != Teuchos::VERB_NONE) {
805 // Convention is to start describe() implementations with a tab.
806 OSTab tab0(out);
807 if (myRank == 0) {
808 out << "\"Tpetra::Details::CooMatrix\":" << endl;
809 }
810 OSTab tab1(out);
811 if (myRank == 0) {
812 out << "Template parameters:" << endl;
813 {
814 OSTab tab2(out);
815 out << "SC: " << TypeNameTraits<SC>::name() << endl
816 << "LO: " << TypeNameTraits<LO>::name() << endl
817 << "GO: " << TypeNameTraits<GO>::name() << endl
818 << "NT: " << TypeNameTraits<NT>::name() << endl;
819 }
820 if (this->getObjectLabel() != "") {
821 out << "Label: \"" << this->getObjectLabel() << "\"" << endl;
822 }
823 out << "Has Map: " << (this->map_.is_null() ? "false" : "true") << endl;
824 } // if myRank == 0
825
826 // Describe the Map, if it exists.
827 if (!this->map_.is_null()) {
828 if (myRank == 0) {
829 out << "Map:" << endl;
830 }
831 OSTab tab2(out);
832 this->map_->describe(out, vl);
833 }
834
835 // At verbosity > VERB_LOW, each process prints something.
836 if (vl > VERB_LOW) {
837 std::ostringstream os;
838 os << "Process " << myRank << ":" << endl;
839 // OSTab tab3 (os);
840
841 const std::size_t numEnt = this->impl_.getLclNumEntries();
842 os << " Local number of entries: " << numEnt << endl;
843 if (vl > VERB_MEDIUM) {
844 os << " Local entries:" << endl;
845 // OSTab tab4 (os);
846 this->impl_.forAllEntries([&os](const GO row, const GO col, const SC& val) {
847 os << " {"
848 << "row: " << row
849 << ", col: " << col
850 << ", val: " << val
851 << "}" << endl;
852 });
853 }
854 gathervPrint(out, os.str(), *comm);
855 }
856 } // vl != Teuchos::VERB_NONE
857 }
858
859 private:
868 Teuchos::RCP<const map_type>
869 buildMap(const ::Teuchos::RCP<const ::Teuchos::Comm<int> >& comm) {
870 using ::Teuchos::outArg;
871 using ::Teuchos::rcp;
872 using ::Teuchos::REDUCE_MIN;
873 using ::Teuchos::reduceAll;
875 // const char prefix[] = "Tpetra::Details::CooMatrix::buildMap: ";
876
877 // Processes where comm is null don't participate in the Map.
878 if (comm.is_null()) {
879 return ::Teuchos::null;
880 }
881
882 // mfh 17 Jan 2017: We just happen to use row indices, because
883 // that's what Tpetra::CrsMatrix currently uses. That's probably
884 // not the best thing to use, but it's not bad for commonly
885 // encountered matrices. A better more general approach might be
886 // to hash (row index, column index) pairs to a global index. One
887 // could make that unique by doing a parallel scan at map
888 // construction time.
889
890 std::vector<GO> rowInds;
891 const GO lclMinGblRowInd = this->impl_.getMyGlobalRowIndices(rowInds);
892
893 // Compute the globally min row index for the "index base."
894 GO gblMinGblRowInd = 0; // output argument
897 const GO indexBase = gblMinGblRowInd;
898 const GST INV = Tpetra::Details::OrdinalTraits<GST>::invalid();
899 return rcp(new map_type(INV, rowInds.data(), rowInds.size(),
900 indexBase, comm));
901 }
902
903 protected:
907 virtual size_t constantNumberOfPackets() const {
908 return static_cast<size_t>(0);
909 }
910
914 virtual bool
915 checkSizes(const ::Tpetra::SrcDistObject& source) {
916 using std::endl;
918 const char prefix[] = "Tpetra::Details::CooMatrix::checkSizes: ";
919
920 const this_COO_type* src = dynamic_cast<const this_COO_type*>(&source);
921
922 if (src == NULL) {
923 std::ostream& err = markLocalErrorAndGetStream();
924 err << prefix << "The source object of the Import or Export "
925 "must be a CooMatrix with the same template parameters as the "
926 "target object."
927 << endl;
928 } else if (this->map_.is_null()) {
929 std::ostream& err = markLocalErrorAndGetStream();
930 err << prefix << "The target object of the Import or Export "
931 "must be a CooMatrix with a nonnull Map."
932 << endl;
933 }
934 return !(*(this->localError_));
935 }
936
939 typename ::Tpetra::DistObject<char, LO, GO, NT>::buffer_device_type;
940
941 virtual void
942 copyAndPermute(const ::Tpetra::SrcDistObject& sourceObject,
943 const size_t numSameIDs,
944 const Kokkos::DualView<const LO*,
946 const Kokkos::DualView<const LO*,
948 const CombineMode /* CM */) {
949 using std::endl;
951 const char prefix[] = "Tpetra::Details::CooMatrix::copyAndPermute: ";
952
953 // There's no communication in this method, so it's safe just to
954 // return on error.
955
956 if (*(this->localError_)) {
957 std::ostream& err = this->markLocalErrorAndGetStream();
958 err << prefix << "The target object of the Import or Export is "
959 "already in an error state."
960 << endl;
961 return;
962 }
963
964 const this_COO_type* src = dynamic_cast<const this_COO_type*>(&sourceObject);
965 if (src == nullptr) {
966 std::ostream& err = this->markLocalErrorAndGetStream();
967 err << prefix << "Input argument 'sourceObject' is not a CooMatrix."
968 << endl;
969 return;
970 }
971
972 const size_t numPermuteIDs =
973 static_cast<size_t>(permuteToLIDs.extent(0));
974 if (numPermuteIDs != static_cast<size_t>(permuteFromLIDs.extent(0))) {
975 std::ostream& err = this->markLocalErrorAndGetStream();
976 err << prefix << "permuteToLIDs.extent(0) = "
977 << numPermuteIDs << " != permuteFromLIDs.extent(0) = "
978 << permuteFromLIDs.extent(0) << "." << endl;
979 return;
980 }
981 if (sizeof(int) <= sizeof(size_t) &&
982 numPermuteIDs > static_cast<size_t>(std::numeric_limits<int>::max())) {
983 std::ostream& err = this->markLocalErrorAndGetStream();
984 err << prefix << "numPermuteIDs = " << numPermuteIDs
985 << ", a size_t, overflows int." << endl;
986 return;
987 }
988
989 // Even though this is an std::set, we can start with numSameIDs
990 // just by iterating through the first entries of the set.
991
992 if (sizeof(int) <= sizeof(size_t) &&
993 numSameIDs > static_cast<size_t>(std::numeric_limits<int>::max())) {
994 std::ostream& err = this->markLocalErrorAndGetStream();
995 err << prefix << "numSameIDs = " << numSameIDs
996 << ", a size_t, overflows int." << endl;
997 return;
998 }
999
1000 //
1001 // Copy in entries from any initial rows with the same global row indices.
1002 //
1003 const LO numSame = static_cast<int>(numSameIDs);
1004 // Count of local row indices encountered here with invalid global
1005 // row indices. If nonzero, something went wrong. If something
1006 // did go wrong, we'll defer responding until the end of this
1007 // method, so we can print as much useful info as possible.
1008 LO numInvalidSameRows = 0;
1009 for (LO lclRow = 0; lclRow < numSame; ++lclRow) {
1010 // All numSame initial rows have the same global index in both
1011 // source and target Maps, so we only need to convert to global
1012 // once.
1013 const GO gblRow = this->map_->getGlobalElement(lclRow);
1014 if (gblRow == ::Tpetra::Details::OrdinalTraits<GO>::invalid()) {
1016 continue;
1017 } else {
1018 this->impl_.mergeIntoRow(gblRow, src->impl_, gblRow);
1019 }
1020 }
1021
1022 //
1023 // Copy in entries from remaining rows that are permutations, that
1024 // is, that live in both the source and target Maps, but aren't
1025 // included in the "same" list (see above).
1026 //
1027 const LO numPermute = static_cast<int>(numPermuteIDs);
1028 // Count of local "from" row indices encountered here with invalid
1029 // global row indices. If nonzero, something went wrong. If
1030 // something did go wrong, we'll defer responding until the end of
1031 // this method, so we can print as much useful info as possible.
1032 LO numInvalidRowsFrom = 0;
1033 // Count of local "to" row indices encountered here with invalid
1034 // global row indices. If nonzero, something went wrong. If
1035 // something did go wrong, we'll defer responding until the end of
1036 // this method, so we can print as much useful info as possible.
1037 LO numInvalidRowsTo = 0;
1038
1039 TEUCHOS_ASSERT(!permuteFromLIDs.need_sync_host());
1040 TEUCHOS_ASSERT(!permuteToLIDs.need_sync_host());
1041 auto permuteFromLIDs_h = permuteFromLIDs.view_host();
1042 auto permuteToLIDs_h = permuteToLIDs.view_host();
1043
1044 for (LO k = 0; k < numPermute; ++k) {
1045 const LO lclRowFrom = permuteFromLIDs_h[k];
1046 const LO lclRowTo = permuteToLIDs_h[k];
1047 const GO gblRowFrom = src->map_->getGlobalElement(lclRowFrom);
1048 const GO gblRowTo = this->map_->getGlobalElement(lclRowTo);
1049
1050 bool bothConversionsValid = true;
1051 if (gblRowFrom == ::Tpetra::Details::OrdinalTraits<GO>::invalid()) {
1053 bothConversionsValid = false;
1054 }
1055 if (gblRowTo == ::Tpetra::Details::OrdinalTraits<GO>::invalid()) {
1057 bothConversionsValid = false;
1058 }
1060 this->impl_.mergeIntoRow(gblRowTo, src->impl_, gblRowFrom);
1061 }
1062 }
1063
1064 // Print info if any errors occurred.
1065 if (numInvalidSameRows != 0 || numInvalidRowsFrom != 0 ||
1066 numInvalidRowsTo != 0) {
1067 // Collect and print all the invalid input row indices, for the
1068 // "same," "from," and "to" lists.
1069 std::vector<std::pair<LO, GO> > invalidSameRows;
1071 std::vector<std::pair<LO, GO> > invalidRowsFrom;
1073 std::vector<std::pair<LO, GO> > invalidRowsTo;
1075
1076 for (LO lclRow = 0; lclRow < numSame; ++lclRow) {
1077 // All numSame initial rows have the same global index in both
1078 // source and target Maps, so we only need to convert to global
1079 // once.
1080 const GO gblRow = this->map_->getGlobalElement(lclRow);
1081 if (gblRow == ::Tpetra::Details::OrdinalTraits<GO>::invalid()) {
1082 invalidSameRows.push_back({lclRow, gblRow});
1083 }
1084 }
1085
1086 for (LO k = 0; k < numPermute; ++k) {
1087 const LO lclRowFrom = permuteFromLIDs_h[k];
1088 const LO lclRowTo = permuteToLIDs_h[k];
1089 const GO gblRowFrom = src->map_->getGlobalElement(lclRowFrom);
1090 const GO gblRowTo = this->map_->getGlobalElement(lclRowTo);
1091
1092 if (gblRowFrom == ::Tpetra::Details::OrdinalTraits<GO>::invalid()) {
1094 }
1095 if (gblRowTo == ::Tpetra::Details::OrdinalTraits<GO>::invalid()) {
1096 invalidRowsTo.push_back({lclRowTo, gblRowTo});
1097 }
1098 }
1099
1100 std::ostringstream os;
1101 if (numInvalidSameRows != 0) {
1102 os << "Invalid permute \"same\" (local, global) index pairs: [";
1103 for (std::size_t k = 0; k < invalidSameRows.size(); ++k) {
1104 const auto& p = invalidSameRows[k];
1105 os << "(" << p.first << "," << p.second << ")";
1106 if (k + 1 < invalidSameRows.size()) {
1107 os << ", ";
1108 }
1109 }
1110 os << "]" << std::endl;
1111 }
1112 if (numInvalidRowsFrom != 0) {
1113 os << "Invalid permute \"from\" (local, global) index pairs: [";
1114 for (std::size_t k = 0; k < invalidRowsFrom.size(); ++k) {
1115 const auto& p = invalidRowsFrom[k];
1116 os << "(" << p.first << "," << p.second << ")";
1117 if (k + 1 < invalidRowsFrom.size()) {
1118 os << ", ";
1119 }
1120 }
1121 os << "]" << std::endl;
1122 }
1123 if (numInvalidRowsTo != 0) {
1124 os << "Invalid permute \"to\" (local, global) index pairs: [";
1125 for (std::size_t k = 0; k < invalidRowsTo.size(); ++k) {
1126 const auto& p = invalidRowsTo[k];
1127 os << "(" << p.first << "," << p.second << ")";
1128 if (k + 1 < invalidRowsTo.size()) {
1129 os << ", ";
1130 }
1131 }
1132 os << "]" << std::endl;
1133 }
1134
1135 std::ostream& err = this->markLocalErrorAndGetStream();
1136 err << prefix << os.str();
1137 return;
1138 }
1139 }
1140
1141 virtual void
1142 packAndPrepare(const ::Tpetra::SrcDistObject& sourceObject,
1143 const Kokkos::DualView<const local_ordinal_type*,
1145 Kokkos::DualView<packet_type*,
1146 buffer_device_type>& exports,
1147 Kokkos::DualView<size_t*,
1150 size_t& constantNumPackets) {
1151 using std::endl;
1152 using Teuchos::Comm;
1153 using Teuchos::RCP;
1155 const char prefix[] = "Tpetra::Details::CooMatrix::packAndPrepare: ";
1156 const char suffix[] =
1157 " This should never happen. "
1158 "Please report this bug to the Tpetra developers.";
1159
1160 // Tell the caller that different rows may have different numbers
1161 // of matrix entries.
1163
1164 const this_COO_type* src = dynamic_cast<const this_COO_type*>(&sourceObject);
1165 if (src == nullptr) {
1166 std::ostream& err = this->markLocalErrorAndGetStream();
1167 err << prefix << "Input argument 'sourceObject' is not a CooMatrix."
1168 << endl;
1169 } else if (*(src->localError_)) {
1170 std::ostream& err = this->markLocalErrorAndGetStream();
1171 err << prefix << "The source (input) object of the Import or Export "
1172 "is already in an error state on this process."
1173 << endl;
1174 } else if (*(this->localError_)) {
1175 std::ostream& err = this->markLocalErrorAndGetStream();
1176 err << prefix << "The target (output, \"this\") object of the Import "
1177 "or Export is already in an error state on this process."
1178 << endl;
1179 }
1180 // Respond to detected error(s) by resizing 'exports' to zero (so
1181 // we won't be tempted to read it later), and filling
1182 // numPacketsPerLID with zeros.
1183 if (*(this->localError_)) {
1184 // Resize 'exports' to zero, so we won't be tempted to read it.
1185 Details::reallocDualViewIfNeeded(exports, 0, "CooMatrix exports");
1186 // Trick to get around const DualView& being const.
1187 {
1188 auto numPacketsPerLID_tmp = numPacketsPerLID;
1189 numPacketsPerLID_tmp.sync_host();
1190 numPacketsPerLID_tmp.modify_host();
1191 }
1192 // Fill numPacketsPerLID with zeros.
1193 Kokkos::deep_copy(numPacketsPerLID.view_host(), static_cast<size_t>(0));
1194 return;
1195 }
1196
1197 const size_t numExports = exportLIDs.extent(0);
1198 if (numExports == 0) {
1199 Details::reallocDualViewIfNeeded(exports, 0, exports.view_host().label());
1200 return; // nothing to send
1201 }
1202 RCP<const Comm<int> > comm = src->getMap().is_null() ? Teuchos::null : src->getMap()->getComm();
1203 if (comm.is_null() || comm->getSize() == 1) {
1204 if (numExports != static_cast<size_t>(0)) {
1205 std::ostream& err = this->markLocalErrorAndGetStream();
1206 err << prefix << "The input communicator is either null or "
1207 "has only one process, but numExports = "
1208 << numExports << " != 0."
1209 << suffix << endl;
1210 return;
1211 }
1212 // Don't go into the rest of this method unless there are
1213 // actually processes other than the calling process. This is
1214 // because the pack and unpack functions only have nonstub
1215 // implementations if building with MPI.
1216 return;
1217 }
1218
1219 numPacketsPerLID.sync_host();
1220 numPacketsPerLID.modify_host();
1221
1222 TEUCHOS_ASSERT(!exportLIDs.need_sync_host());
1223 auto exportLIDs_h = exportLIDs.view_host();
1224
1225 int totalNumPackets = 0;
1226 size_t numInvalidRowInds = 0;
1227 std::ostringstream errStrm; // current loop iteration's error messages
1228 for (size_t k = 0; k < numExports; ++k) {
1229 const LO lclRow = exportLIDs_h[k];
1230 // We're packing the source object's data, so we need to use the
1231 // source object's Map to convert from local to global indices.
1232 const GO gblRow = src->map_->getGlobalElement(lclRow);
1233 if (gblRow == ::Tpetra::Details::OrdinalTraits<GO>::invalid()) {
1234 // Mark the error later; just count for now.
1235 ++numInvalidRowInds;
1236 numPacketsPerLID.view_host()[k] = 0;
1237 continue;
1238 }
1239
1240 // Count the number of bytes needed to pack the current row of
1241 // the source object.
1242 int numPackets = 0;
1243 const int errCode =
1244 src->impl_.countPackRow(numPackets, gblRow, *comm, &errStrm);
1245 if (errCode != 0) {
1246 std::ostream& err = this->markLocalErrorAndGetStream();
1247 err << prefix << errStrm.str() << endl;
1248 numPacketsPerLID.view_host()[k] = 0;
1249 continue;
1250 }
1251
1252 // Make sure that the total number of packets fits in int.
1253 // MPI requires this.
1254 const long long newTotalNumPackets =
1255 static_cast<long long>(totalNumPackets) +
1256 static_cast<long long>(numPackets);
1257 if (newTotalNumPackets >
1258 static_cast<long long>(std::numeric_limits<int>::max())) {
1259 std::ostream& err = this->markLocalErrorAndGetStream();
1260 err << prefix << "The new total number of packets "
1261 << newTotalNumPackets << " does not fit in int." << endl;
1262 // At this point, we definitely cannot continue. In order to
1263 // leave the output arguments in a rational state, we zero out
1264 // all remaining entries of numPacketsPerLID before returning.
1265 for (size_t k2 = k; k2 < numExports; ++k2) {
1266 numPacketsPerLID.view_host()[k2] = 0;
1267 }
1268 return;
1269 }
1270 numPacketsPerLID.view_host()[k] = static_cast<size_t>(numPackets);
1271 totalNumPackets = static_cast<int>(newTotalNumPackets);
1272 }
1273
1274 // If we found invalid row indices in exportLIDs, go back,
1275 // collect, and report them.
1276 if (numInvalidRowInds != 0) {
1277 std::vector<std::pair<LO, GO> > invalidRowInds;
1278 for (size_t k = 0; k < numExports; ++k) {
1279 const LO lclRow = exportLIDs_h[k];
1280 // We're packing the source object's data, so we need to use
1281 // the source object's Map to convert from local to global
1282 // indices.
1283 const GO gblRow = src->map_->getGlobalElement(lclRow);
1284 if (gblRow == ::Tpetra::Details::OrdinalTraits<GO>::invalid()) {
1285 invalidRowInds.push_back({lclRow, gblRow});
1286 }
1287 }
1288 std::ostringstream os;
1289 os << prefix << "We found " << numInvalidRowInds << " invalid row ind"
1290 << (numInvalidRowInds != static_cast<size_t>(1) ? "ices" : "ex")
1291 << " out of " << numExports << " in exportLIDs. Here is the list "
1292 << " of invalid row indices: [";
1293 for (size_t k = 0; k < invalidRowInds.size(); ++k) {
1294 os << "(LID: " << invalidRowInds[k].first << ", GID: "
1295 << invalidRowInds[k].second << ")";
1296 if (k + 1 < invalidRowInds.size()) {
1297 os << ", ";
1298 }
1299 }
1300 os << "].";
1301
1302 std::ostream& err = this->markLocalErrorAndGetStream();
1303 err << prefix << os.str() << std::endl;
1304 return;
1305 }
1306
1307 {
1308 const bool reallocated =
1309 Details::reallocDualViewIfNeeded(exports, totalNumPackets,
1310 "CooMatrix exports");
1311 if (reallocated) {
1312 exports.sync_host(); // make sure alloc'd on host
1313 }
1314 }
1315 exports.modify_host();
1316
1317 // FIXME (mfh 17 Jan 2017) packTriples wants three arrays, not a
1318 // single array of structs. For now, we just copy.
1319 std::vector<GO> gblRowInds;
1320 std::vector<GO> gblColInds;
1321 std::vector<SC> vals;
1322
1323 int outBufCurPos = 0;
1324 packet_type* outBuf = exports.view_host().data();
1325 for (size_t k = 0; k < numExports; ++k) {
1326 const LO lclRow = exportLIDs.view_host()[k];
1327 // We're packing the source object's data, so we need to use the
1328 // source object's Map to convert from local to global indices.
1329 const GO gblRow = src->map_->getGlobalElement(lclRow);
1330 // Pack the current row of the source object.
1331 src->impl_.packRow(outBuf, totalNumPackets, outBufCurPos, *comm,
1332 gblRowInds, gblColInds, vals, gblRow);
1333 }
1334 }
1335
1336 virtual void
1337 unpackAndCombine(const Kokkos::DualView<const local_ordinal_type*,
1338 buffer_device_type>& importLIDs,
1339 Kokkos::DualView<packet_type*,
1341 imports,
1342 Kokkos::DualView<size_t*,
1344 numPacketsPerLID,
1345 const size_t /* constantNumPackets */,
1346 const ::Tpetra::CombineMode /* combineMode */) {
1347 using std::endl;
1348 using Teuchos::Comm;
1349 using Teuchos::RCP;
1350 const char prefix[] = "Tpetra::Details::CooMatrix::unpackAndCombine: ";
1351 const char suffix[] =
1352 " This should never happen. "
1353 "Please report this bug to the Tpetra developers.";
1354
1355 TEUCHOS_ASSERT(!importLIDs.need_sync_host());
1356 auto importLIDs_h = importLIDs.view_host();
1357
1358 const std::size_t numImports = importLIDs.extent(0);
1359 if (numImports == 0) {
1360 return; // nothing to receive
1361 } else if (imports.extent(0) == 0) {
1362 std::ostream& err = this->markLocalErrorAndGetStream();
1363 err << prefix << "importLIDs.extent(0) = " << numImports << " != 0, "
1364 << "but imports.extent(0) = 0. This doesn't make sense, because "
1365 << "for every incoming LID, CooMatrix packs at least the count of "
1366 << "triples associated with that LID, even if the count is zero. "
1367 << "importLIDs = [";
1368 for (std::size_t k = 0; k < numImports; ++k) {
1369 err << importLIDs_h[k];
1370 if (k + 1 < numImports) {
1371 err << ", ";
1372 }
1373 }
1374 err << "]. " << suffix << endl;
1375 return;
1376 }
1377
1378 RCP<const Comm<int> > comm = this->getMap().is_null() ? Teuchos::null : this->getMap()->getComm();
1379 if (comm.is_null() || comm->getSize() == 1) {
1380 if (numImports != static_cast<size_t>(0)) {
1381 std::ostream& err = this->markLocalErrorAndGetStream();
1382 err << prefix << "The input communicator is either null or "
1383 "has only one process, but numImports = "
1384 << numImports << " != 0."
1385 << suffix << endl;
1386 return;
1387 }
1388 // Don't go into the rest of this method unless there are
1389 // actually processes other than the calling process. This is
1390 // because the pack and unpack functions only have nonstub
1391 // implementations if building with MPI.
1392 return;
1393 }
1394
1395 // Make sure that the length of 'imports' fits in int.
1396 // This is ultimately an MPI restriction.
1397 if (static_cast<size_t>(imports.extent(0)) >
1398 static_cast<size_t>(std::numeric_limits<int>::max())) {
1399 std::ostream& err = this->markLocalErrorAndGetStream();
1400 err << prefix << "imports.extent(0) = "
1401 << imports.extent(0) << " does not fit in int." << endl;
1402 return;
1403 }
1404 const int inBufSize = static_cast<int>(imports.extent(0));
1405
1406 if (imports.need_sync_host()) {
1407 imports.sync_host();
1408 }
1409 if (numPacketsPerLID.need_sync_host()) {
1410 numPacketsPerLID.sync_host();
1411 }
1412 auto imports_h = imports.view_host();
1413 auto numPacketsPerLID_h = numPacketsPerLID.view_host();
1414
1415 // FIXME (mfh 17,24 Jan 2017) packTriples wants three arrays, not a
1416 // single array of structs. For now, we just copy.
1417 std::vector<GO> gblRowInds;
1418 std::vector<GO> gblColInds;
1419 std::vector<SC> vals;
1420
1421 const packet_type* inBuf = imports_h.data();
1422 int inBufCurPos = 0;
1423 size_t numInvalidRowInds = 0;
1424 int errCode = 0;
1425 std::ostringstream errStrm; // for unpack* error output.
1426 for (size_t k = 0; k < numImports; ++k) {
1427 const LO lclRow = importLIDs_h(k);
1428 const GO gblRow = this->map_->getGlobalElement(lclRow);
1429 if (gblRow == ::Tpetra::Details::OrdinalTraits<GO>::invalid()) {
1430 ++numInvalidRowInds;
1431 continue;
1432 }
1433
1434 // Remember where we were, so we don't overrun the buffer
1435 // length. inBufCurPos is an in/out argument of unpackTriples*.
1436 const int origInBufCurPos = inBufCurPos;
1437
1438 int numEnt = 0; // output argument of unpackTriplesCount
1439 errCode = unpackTriplesCount(inBuf, inBufSize, inBufCurPos,
1440 numEnt, *comm, &errStrm);
1441 if (errCode != 0 || numEnt < 0 || inBufCurPos < origInBufCurPos) {
1442 std::ostream& err = this->markLocalErrorAndGetStream();
1443
1444 err << prefix << "In unpack loop, k=" << k << ": ";
1445 if (errCode != 0) {
1446 err << " unpackTriplesCount returned errCode = " << errCode
1447 << " != 0." << endl;
1448 }
1449 if (numEnt < 0) {
1450 err << " unpackTriplesCount returned errCode = 0, but numEnt = "
1451 << numEnt << " < 0." << endl;
1452 }
1453 if (inBufCurPos < origInBufCurPos) {
1454 err << " After unpackTriplesCount, inBufCurPos = " << inBufCurPos
1455 << " < origInBufCurPos = " << origInBufCurPos << "." << endl;
1456 }
1457 err << " unpackTriplesCount report: " << errStrm.str() << endl;
1458 err << suffix << endl;
1459
1460 // We only continue in a debug build, because the above error
1461 // messages could consume too much memory and cause an
1462 // out-of-memory error, without actually printing. Printing
1463 // everything is useful in a debug build, but not so much in a
1464 // release build.
1465#ifdef HAVE_TPETRA_DEBUG
1466 // Clear out the current error stream, so we don't accumulate
1467 // over loop iterations.
1468 errStrm.str("");
1469 continue;
1470#else
1471 return;
1472#endif // HAVE_TPETRA_DEBUG
1473 }
1474
1475 // FIXME (mfh 17,24 Jan 2017) packTriples wants three arrays,
1476 // not a single array of structs. For now, we just copy.
1477 gblRowInds.resize(numEnt);
1478 gblColInds.resize(numEnt);
1479 vals.resize(numEnt);
1480
1481 errCode = unpackTriples(inBuf, inBufSize, inBufCurPos,
1482 gblRowInds.data(), gblColInds.data(),
1483 vals.data(), numEnt, *comm, &errStrm);
1484 if (errCode != 0) {
1485 std::ostream& err = this->markLocalErrorAndGetStream();
1486 err << prefix << "unpackTriples returned errCode = "
1487 << errCode << " != 0. It reports: " << errStrm.str()
1488 << endl;
1489 // We only continue in a debug build, because the above error
1490 // messages could consume too much memory and cause an
1491 // out-of-memory error, without actually printing. Printing
1492 // everything is useful in a debug build, but not so much in a
1493 // release build.
1494#ifdef HAVE_TPETRA_DEBUG
1495 // Clear out the current error stream, so we don't accumulate
1496 // over loop iterations.
1497 errStrm.str("");
1498 continue;
1499#else
1500 return;
1501#endif // HAVE_TPETRA_DEBUG
1502 }
1503 this->sumIntoGlobalValues(gblRowInds.data(), gblColInds.data(),
1504 vals.data(), numEnt);
1505 }
1506
1507 // If we found invalid row indices in exportLIDs, go back,
1508 // collect, and report them.
1509 if (numInvalidRowInds != 0) {
1510 // Mark the error now, before we possibly run out of memory.
1511 // The latter could raise an exception (e.g., std::bad_alloc),
1512 // but at least we would get the error state right.
1513 std::ostream& err = this->markLocalErrorAndGetStream();
1514
1515 std::vector<std::pair<LO, GO> > invalidRowInds;
1516 for (size_t k = 0; k < numImports; ++k) {
1517 const LO lclRow = importLIDs_h(k);
1518 const GO gblRow = this->map_->getGlobalElement(lclRow);
1519 if (gblRow == ::Tpetra::Details::OrdinalTraits<GO>::invalid()) {
1520 invalidRowInds.push_back({lclRow, gblRow});
1521 }
1522 }
1523
1524 err << prefix << "We found " << numInvalidRowInds << " invalid row ind"
1525 << (numInvalidRowInds != static_cast<size_t>(1) ? "ices" : "ex")
1526 << " out of " << numImports << " in importLIDs. Here is the list "
1527 << " of invalid row indices: [";
1528 for (size_t k = 0; k < invalidRowInds.size(); ++k) {
1529 err << "(LID: " << invalidRowInds[k].first << ", GID: "
1530 << invalidRowInds[k].second << ")";
1531 if (k + 1 < invalidRowInds.size()) {
1532 err << ", ";
1533 }
1534 }
1535 err << "].";
1536 return;
1537 }
1538 }
1539};
1540
1541} // namespace Details
1542} // namespace Tpetra
1543
1544#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).