10 #ifndef TPETRA_DETAILS_COOMATRIX_HPP
11 #define TPETRA_DETAILS_COOMATRIX_HPP
18 #include "TpetraCore_config.h"
19 #include "Tpetra_Details_PackTriples.hpp"
20 #include "Tpetra_DistObject.hpp"
23 #include "Teuchos_TypeNameTraits.hpp"
25 #include <initializer_list>
29 #include <type_traits>
42 template<
class IndexType>
52 template<
class IndexType>
58 return (x.row < y.row) || (x.row == y.row && x.col < y.col);
64 template<
class SC,
class GO>
74 typedef std::map<CooGraphEntry<GO>, SC,
79 entries_type entries_;
103 auto result = this->entries_.insert ({ij, val});
104 if (! result.second) {
105 result.first->second += val;
119 const GO gblColInds[],
121 const std::size_t numEnt)
123 for (std::size_t k = 0; k < numEnt; ++k) {
128 const SC val = vals[k];
129 auto result = this->entries_.insert ({ij, val});
130 if (! result.second) {
131 result.first->second += val;
140 return this->entries_.size ();
149 for (
auto iter = this->entries_.begin ();
150 iter != this->entries_.end (); ++iter) {
151 f (iter->first.row, iter->first.col, iter->second);
168 entries_type& tgtEntries = this->entries_;
169 const entries_type& srcEntries = src.entries_;
175 auto srcBeg = srcEntries.lower_bound ({srcGblRow, std::numeric_limits<GO>::min ()});
176 auto srcEnd = srcEntries.upper_bound ({srcGblRow+1, std::numeric_limits<GO>::min ()});
177 auto tgtBeg = tgtEntries.lower_bound ({tgtGblRow, std::numeric_limits<GO>::min ()});
178 auto tgtEnd = tgtEntries.upper_bound ({tgtGblRow+1, std::numeric_limits<GO>::min ()});
182 if (srcBeg != srcEnd) {
183 for (
auto tgtCur = tgtBeg; tgtCur != tgtEnd; ++tgtCur) {
184 auto srcCur = srcBeg;
185 while (srcCur != srcEnd && srcCur->first.col < tgtCur->first.col) {
197 if (srcCur != srcEnd) {
198 if (srcCur->first.col == tgtCur->first.col) {
199 tgtCur->second += srcCur->second;
206 (void) tgtEntries.insert (tgtCur, *srcCur);
225 const ::Teuchos::Comm<int>& comm,
226 std::ostream* errStrm = NULL)
const
228 using ::Tpetra::Details::countPackTriples;
229 using ::Tpetra::Details::countPackTriplesCount;
231 const char prefix[] =
"Tpetra::Details::Impl::CooMatrixImpl::countPackRow: ";
232 #ifdef HAVE_TPETRACORE_MPI
233 int errCode = MPI_SUCCESS;
236 #endif // HAVE_TPETRACORE_MPI
239 const GO minGO = std::numeric_limits<GO>::min ();
240 auto beg = this->entries_.lower_bound ({gblRow, minGO});
241 auto end = this->entries_.upper_bound ({gblRow+1, minGO});
243 for (
auto iter = beg; iter != end; ++iter) {
245 if (numEnt == std::numeric_limits<int>::max ()) {
246 if (errStrm != NULL) {
247 *errStrm << prefix <<
"In (global) row " << gblRow <<
", the number "
248 "of entries thus far, numEnt = " << numEnt <<
", has reached the "
249 "maximum int value. We need to store this count as int for MPI's "
256 int numPacketsForCount = 0;
261 if (errStrm != NULL) {
262 *errStrm << prefix <<
"countPackTriplesCount "
263 "returned errCode = " << errCode <<
" != 0." << endl;
267 if (numPacketsForCount < 0) {
268 if (errStrm != NULL) {
269 *errStrm << prefix <<
"countPackTriplesCount returned "
270 "numPacketsForCount = " << numPacketsForCount <<
" < 0." << endl;
276 int numPacketsForTriples = 0;
278 errCode = countPackTriples<SC, GO> (numEnt, comm, numPacketsForTriples);
279 TEUCHOS_TEST_FOR_EXCEPTION
280 (errCode != 0, std::runtime_error, prefix <<
"countPackTriples "
281 "returned errCode = " << errCode <<
" != 0.");
282 TEUCHOS_TEST_FOR_EXCEPTION
283 (numPacketsForTriples < 0, std::logic_error, prefix <<
"countPackTriples "
284 "returned numPacketsForTriples = " << numPacketsForTriples <<
" < 0.");
287 numPackets = numPacketsForCount + numPacketsForTriples;
307 const int outBufSize,
309 const ::Teuchos::Comm<int>& comm,
310 std::vector<GO>& gblRowInds,
311 std::vector<GO>& gblColInds,
312 std::vector<SC>& vals,
313 const GO gblRow)
const
315 using ::Tpetra::Details::packTriples;
316 using ::Tpetra::Details::packTriplesCount;
317 const char prefix[] =
"Tpetra::Details::Impl::CooMatrixImpl::packRow: ";
319 const GO minGO = std::numeric_limits<GO>::min ();
320 auto beg = this->entries_.lower_bound ({gblRow, minGO});
321 auto end = this->entries_.upper_bound ({gblRow+1, minGO});
325 gblRowInds.resize (0);
326 gblColInds.resize (0);
330 for (
auto iter = beg; iter != end; ++iter) {
331 gblRowInds.push_back (iter->first.row);
332 gblColInds.push_back (iter->first.col);
333 vals.push_back (iter->second);
335 TEUCHOS_TEST_FOR_EXCEPTION
336 (numEnt == std::numeric_limits<int>::max (), std::runtime_error, prefix
337 <<
"In (global) row " << gblRow <<
", the number of entries thus far, "
338 "numEnt = " << numEnt <<
", has reached the maximum int value. "
339 "We need to store this count as int for MPI's sake.");
345 TEUCHOS_TEST_FOR_EXCEPTION
346 (errCode != 0, std::runtime_error, prefix
347 <<
"In (global) row " << gblRow <<
", packTriplesCount returned "
348 "errCode = " << errCode <<
" != 0.");
360 TEUCHOS_TEST_FOR_EXCEPTION
361 (errCode != 0, std::runtime_error, prefix <<
"In (global) row "
362 << gblRow <<
", packTriples returned errCode = " << errCode
379 GO lclMinRowInd = std::numeric_limits<GO>::max ();
380 for (
typename entries_type::const_iterator iter = this->entries_.begin ();
381 iter != this->entries_.end (); ++iter) {
382 const GO rowInd = iter->first.row;
383 if (rowInd < lclMinRowInd) {
384 lclMinRowInd = rowInd;
386 if (rowInds.empty () || rowInds.back () != rowInd) {
387 rowInds.push_back (rowInd);
393 template<
class OffsetType>
395 buildCrs (std::vector<OffsetType>& rowOffsets,
399 static_assert (std::is_integral<OffsetType>::value,
400 "OffsetType must be a built-in integer type.");
408 rowOffsets.push_back (0);
411 typename entries_type::const_iterator iter = this->entries_.begin ();
412 GO prevGblRowInd = iter->first.row;
415 for ( ; iter != this->entries_.end (); ++iter, ++k) {
416 const GO gblRowInd = iter->first.row;
417 if (k == 0 || gblRowInd != prevGblRowInd) {
421 rowOffsets.push_back (k);
422 prevGblRowInd = gblRowInd;
424 gblColInds[k] = iter->first.col;
426 static_assert (std::is_same<
typename std::decay<decltype (iter->second)>::type, SC>::value,
427 "The type of iter->second != SC.");
428 vals[k] = iter->second;
430 rowOffsets.push_back (static_cast<OffsetType> (numEnt));
446 template<
class OffsetType,
class LO>
451 std::function<LO (
const GO)> gblToLcl)
const
453 static_assert (std::is_integral<OffsetType>::value,
454 "OffsetType must be a built-in integer type.");
455 static_assert (std::is_integral<LO>::value,
456 "LO must be a built-in integer type.");
464 rowOffsets.push_back (0);
467 typename entries_type::const_iterator iter = this->entries_.begin ();
468 GO prevGblRowInd = iter->first.row;
471 for ( ; iter != this->entries_.end (); ++iter, ++k) {
472 const GO gblRowInd = iter->first.row;
473 if (k == 0 || gblRowInd != prevGblRowInd) {
477 rowOffsets.push_back (k);
478 prevGblRowInd = gblRowInd;
480 lclColInds[k] = gblToLcl (iter->first.col);
481 vals[k] = iter->second;
483 rowOffsets.push_back (static_cast<OffsetType> (numEnt));
548 typedef LO local_ordinal_type;
549 typedef GO global_ordinal_type;
550 typedef NT node_type;
551 typedef typename NT::device_type device_type;
553 typedef ::Tpetra::Map<local_ordinal_type, global_ordinal_type, node_type>
map_type;
557 typedef ::Tpetra::DistObject<
packet_type, local_ordinal_type,
558 global_ordinal_type, node_type>
base_type;
571 localError_ (new bool (false)),
572 errs_ (new std::shared_ptr<std::ostringstream> ())
584 localError_ (new bool (false)),
585 errs_ (new std::shared_ptr<std::ostringstream> ())
602 this->impl_.sumIntoGlobalValue (gblRowInd, gblColInd, val);
615 const GO gblColInds[],
617 const std::size_t numEnt)
619 this->impl_.sumIntoGlobalValues (gblRowInds, gblColInds, vals, numEnt);
625 std::initializer_list<GO> gblColInds,
626 std::initializer_list<SC> vals,
627 const std::size_t numEnt)
629 this->impl_.sumIntoGlobalValues (gblRowInds.begin (), gblColInds.begin (),
630 vals.begin (), numEnt);
637 return this->impl_.getLclNumEntries ();
640 template<
class OffsetType>
642 buildCrs (::Kokkos::View<OffsetType*, device_type>& rowOffsets,
643 ::Kokkos::View<GO*, device_type>& gblColInds,
644 ::Kokkos::View<typename ::Kokkos::ArithTraits<SC>::val_type*, device_type>& vals)
646 static_assert (std::is_integral<OffsetType>::value,
647 "OffsetType must be a built-in integer type.");
648 using ::Kokkos::create_mirror_view;
650 using ::Kokkos::View;
651 typedef typename ::Kokkos::ArithTraits<SC>::val_type ISC;
655 gblColInds = View<GO*, device_type> (
"gblColInds", numEnt);
656 vals = View<ISC*, device_type> (
"vals", numEnt);
657 auto gblColInds_h = create_mirror_view (gblColInds);
658 auto vals_h = create_mirror_view (vals);
660 std::vector<std::size_t> rowOffsetsSV;
661 this->impl_.buildCrs (rowOffsetsSV,
662 gblColInds_h.data (),
665 View<OffsetType*, device_type> (
"rowOffsets", rowOffsetsSV.size ());
666 typename View<OffsetType*, device_type>::HostMirror
667 rowOffsets_h (rowOffsetsSV.data (), rowOffsetsSV.size ());
687 if (comm.is_null ()) {
688 this->
map_ = ::Teuchos::null;
691 this->
map_ = this->buildMap (comm);
706 TEUCHOS_TEST_FOR_EXCEPTION
707 (this->
getMap ().is_null (), std::runtime_error,
"Tpetra::Details::"
708 "CooMatrix::fillComplete: This object does not yet have a Map. "
709 "You must call the version of fillComplete "
710 "that takes an input communicator.");
750 return ((*errs_).get () == NULL) ? std::string (
"") : (*errs_)->str ();
766 std::shared_ptr<bool> localError_;
775 std::shared_ptr<std::shared_ptr<std::ostringstream> > errs_;
779 markLocalErrorAndGetStream ()
781 * (this->localError_) =
true;
782 if ((*errs_).get () == NULL) {
783 *errs_ = std::shared_ptr<std::ostringstream> (
new std::ostringstream ());
792 using Teuchos::TypeNameTraits;
794 std::ostringstream os;
795 os <<
"\"Tpetra::Details::CooMatrix\": {"
796 <<
"SC: " << TypeNameTraits<SC>::name ()
797 <<
", LO: " << TypeNameTraits<LO>::name ()
798 <<
", GO: " << TypeNameTraits<GO>::name ()
799 <<
", NT: " << TypeNameTraits<NT>::name ();
800 if (this->getObjectLabel () !=
"") {
801 os <<
", Label: \"" << this->getObjectLabel () <<
"\"";
803 os <<
", Has Map: " << (this->
map_.is_null () ?
"false" :
"true")
812 const Teuchos::EVerbosityLevel verbLevel =
813 Teuchos::Describable::verbLevel_default)
const
815 using ::Tpetra::Details::gathervPrint;
816 using ::Teuchos::EVerbosityLevel;
817 using ::Teuchos::OSTab;
818 using ::Teuchos::TypeNameTraits;
819 using ::Teuchos::VERB_DEFAULT;
820 using ::Teuchos::VERB_LOW;
821 using ::Teuchos::VERB_MEDIUM;
824 const auto vl = (verbLevel == VERB_DEFAULT) ? VERB_LOW : verbLevel;
826 auto comm = this->
getMap ().is_null () ?
827 Teuchos::null : this->
getMap ()->getComm ();
828 const int myRank = comm.is_null () ? 0 : comm->getRank ();
831 if (vl != Teuchos::VERB_NONE) {
835 out <<
"\"Tpetra::Details::CooMatrix\":" << endl;
839 out <<
"Template parameters:" << endl;
842 out <<
"SC: " << TypeNameTraits<SC>::name () << endl
843 <<
"LO: " << TypeNameTraits<LO>::name () << endl
844 <<
"GO: " << TypeNameTraits<GO>::name () << endl
845 <<
"NT: " << TypeNameTraits<NT>::name () << endl;
847 if (this->getObjectLabel () !=
"") {
848 out <<
"Label: \"" << this->getObjectLabel () <<
"\"" << endl;
850 out <<
"Has Map: " << (this->
map_.is_null () ?
"false" :
"true") << endl;
854 if (! this->
map_.is_null ()) {
856 out <<
"Map:" << endl;
859 this->
map_->describe (out, vl);
864 std::ostringstream os;
865 os <<
"Process " << myRank <<
":" << endl;
868 const std::size_t numEnt = this->impl_.getLclNumEntries ();
869 os <<
" Local number of entries: " << numEnt << endl;
870 if (vl > VERB_MEDIUM) {
871 os <<
" Local entries:" << endl;
873 this->impl_.forAllEntries ([&os] (
const GO row,
const GO col,
const SC& val) {
895 Teuchos::RCP<const map_type>
896 buildMap (const ::Teuchos::RCP<const ::Teuchos::Comm<int> >& comm)
898 using ::Teuchos::outArg;
899 using ::Teuchos::rcp;
900 using ::Teuchos::REDUCE_MIN;
901 using ::Teuchos::reduceAll;
902 typedef ::Tpetra::global_size_t GST;
906 if (comm.is_null ()) {
907 return ::Teuchos::null;
918 std::vector<GO> rowInds;
919 const GO lclMinGblRowInd = this->impl_.getMyGlobalRowIndices (rowInds);
922 GO gblMinGblRowInd = 0;
923 reduceAll<int, GO> (*comm, REDUCE_MIN, lclMinGblRowInd,
924 outArg (gblMinGblRowInd));
925 const GO indexBase = gblMinGblRowInd;
926 const GST INV = Tpetra::Details::OrdinalTraits<GST>::invalid ();
927 return rcp (
new map_type (INV, rowInds.data (), rowInds.size (),
936 return static_cast<size_t> (0);
947 const char prefix[] =
"Tpetra::Details::CooMatrix::checkSizes: ";
949 const this_COO_type* src =
dynamic_cast<const this_COO_type*
> (&source);
952 std::ostream& err = markLocalErrorAndGetStream ();
953 err << prefix <<
"The source object of the Import or Export "
954 "must be a CooMatrix with the same template parameters as the "
955 "target object." << endl;
957 else if (this->
map_.is_null ()) {
958 std::ostream& err = markLocalErrorAndGetStream ();
959 err << prefix <<
"The target object of the Import or Export "
960 "must be a CooMatrix with a nonnull Map." << endl;
962 return ! (* (this->localError_));
967 typename ::Tpetra::DistObject<char, LO, GO, NT>::buffer_device_type;
971 (const ::Tpetra::SrcDistObject& sourceObject,
972 const size_t numSameIDs,
973 const Kokkos::DualView<
const LO*,
975 const Kokkos::DualView<
const LO*,
981 const char prefix[] =
"Tpetra::Details::CooMatrix::copyAndPermute: ";
986 if (* (this->localError_)) {
987 std::ostream& err = this->markLocalErrorAndGetStream ();
988 err << prefix <<
"The target object of the Import or Export is "
989 "already in an error state." << endl;
993 const this_COO_type* src =
dynamic_cast<const this_COO_type*
> (&sourceObject);
994 if (src ==
nullptr) {
995 std::ostream& err = this->markLocalErrorAndGetStream ();
996 err << prefix <<
"Input argument 'sourceObject' is not a CooMatrix."
1001 const size_t numPermuteIDs =
1002 static_cast<size_t> (permuteToLIDs.extent (0));
1003 if (numPermuteIDs != static_cast<size_t> (permuteFromLIDs.extent (0))) {
1004 std::ostream& err = this->markLocalErrorAndGetStream ();
1005 err << prefix <<
"permuteToLIDs.extent(0) = "
1006 << numPermuteIDs <<
" != permuteFromLIDs.extent(0) = "
1007 << permuteFromLIDs.extent (0) <<
"." << endl;
1010 if (
sizeof (
int) <=
sizeof (
size_t) &&
1011 numPermuteIDs > static_cast<size_t> (std::numeric_limits<int>::max ())) {
1012 std::ostream& err = this->markLocalErrorAndGetStream ();
1013 err << prefix <<
"numPermuteIDs = " << numPermuteIDs
1014 <<
", a size_t, overflows int." << endl;
1021 if (
sizeof (
int) <=
sizeof (
size_t) &&
1022 numSameIDs > static_cast<size_t> (std::numeric_limits<int>::max ())) {
1023 std::ostream& err = this->markLocalErrorAndGetStream ();
1024 err << prefix <<
"numSameIDs = " << numSameIDs
1025 <<
", a size_t, overflows int." << endl;
1032 const LO numSame =
static_cast<int> (numSameIDs);
1037 LO numInvalidSameRows = 0;
1038 for (LO lclRow = 0; lclRow < numSame; ++lclRow) {
1042 const GO gblRow = this->
map_->getGlobalElement (lclRow);
1043 if (gblRow == ::Tpetra::Details::OrdinalTraits<GO>::invalid ()) {
1044 ++numInvalidSameRows;
1048 this->impl_.mergeIntoRow (gblRow, src->impl_, gblRow);
1057 const LO numPermute =
static_cast<int> (numPermuteIDs);
1062 LO numInvalidRowsFrom = 0;
1067 LO numInvalidRowsTo = 0;
1069 TEUCHOS_ASSERT( ! permuteFromLIDs.need_sync_host () );
1070 TEUCHOS_ASSERT( ! permuteToLIDs.need_sync_host () );
1071 auto permuteFromLIDs_h = permuteFromLIDs.view_host ();
1072 auto permuteToLIDs_h = permuteToLIDs.view_host ();
1074 for (LO k = 0; k < numPermute; ++k) {
1075 const LO lclRowFrom = permuteFromLIDs_h[k];
1076 const LO lclRowTo = permuteToLIDs_h[k];
1077 const GO gblRowFrom = src->map_->getGlobalElement (lclRowFrom);
1078 const GO gblRowTo = this->
map_->getGlobalElement (lclRowTo);
1080 bool bothConversionsValid =
true;
1081 if (gblRowFrom == ::Tpetra::Details::OrdinalTraits<GO>::invalid ()) {
1082 ++numInvalidRowsFrom;
1083 bothConversionsValid =
false;
1085 if (gblRowTo == ::Tpetra::Details::OrdinalTraits<GO>::invalid ()) {
1087 bothConversionsValid =
false;
1089 if (bothConversionsValid) {
1090 this->impl_.mergeIntoRow (gblRowTo, src->impl_, gblRowFrom);
1095 if (numInvalidSameRows != 0 || numInvalidRowsFrom != 0 ||
1096 numInvalidRowsTo != 0) {
1099 std::vector<std::pair<LO, GO> > invalidSameRows;
1100 invalidSameRows.reserve (numInvalidSameRows);
1101 std::vector<std::pair<LO, GO> > invalidRowsFrom;
1102 invalidRowsFrom.reserve (numInvalidRowsFrom);
1103 std::vector<std::pair<LO, GO> > invalidRowsTo;
1104 invalidRowsTo.reserve (numInvalidRowsTo);
1106 for (LO lclRow = 0; lclRow < numSame; ++lclRow) {
1110 const GO gblRow = this->
map_->getGlobalElement (lclRow);
1111 if (gblRow == ::Tpetra::Details::OrdinalTraits<GO>::invalid ()) {
1112 invalidSameRows.push_back ({lclRow, gblRow});
1116 for (LO k = 0; k < numPermute; ++k) {
1117 const LO lclRowFrom = permuteFromLIDs_h[k];
1118 const LO lclRowTo = permuteToLIDs_h[k];
1119 const GO gblRowFrom = src->map_->getGlobalElement (lclRowFrom);
1120 const GO gblRowTo = this->
map_->getGlobalElement (lclRowTo);
1122 if (gblRowFrom == ::Tpetra::Details::OrdinalTraits<GO>::invalid ()) {
1123 invalidRowsFrom.push_back ({lclRowFrom, gblRowFrom});
1125 if (gblRowTo == ::Tpetra::Details::OrdinalTraits<GO>::invalid ()) {
1126 invalidRowsTo.push_back ({lclRowTo, gblRowTo});
1130 std::ostringstream os;
1131 if (numInvalidSameRows != 0) {
1132 os <<
"Invalid permute \"same\" (local, global) index pairs: [";
1133 for (std::size_t k = 0; k < invalidSameRows.size (); ++k) {
1134 const auto& p = invalidSameRows[k];
1135 os <<
"(" << p.first <<
"," << p.second <<
")";
1136 if (k + 1 < invalidSameRows.size ()) {
1140 os <<
"]" << std::endl;
1142 if (numInvalidRowsFrom != 0) {
1143 os <<
"Invalid permute \"from\" (local, global) index pairs: [";
1144 for (std::size_t k = 0; k < invalidRowsFrom.size (); ++k) {
1145 const auto& p = invalidRowsFrom[k];
1146 os <<
"(" << p.first <<
"," << p.second <<
")";
1147 if (k + 1 < invalidRowsFrom.size ()) {
1151 os <<
"]" << std::endl;
1153 if (numInvalidRowsTo != 0) {
1154 os <<
"Invalid permute \"to\" (local, global) index pairs: [";
1155 for (std::size_t k = 0; k < invalidRowsTo.size (); ++k) {
1156 const auto& p = invalidRowsTo[k];
1157 os <<
"(" << p.first <<
"," << p.second <<
")";
1158 if (k + 1 < invalidRowsTo.size ()) {
1162 os <<
"]" << std::endl;
1165 std::ostream& err = this->markLocalErrorAndGetStream ();
1166 err << prefix << os.str ();
1173 (const ::Tpetra::SrcDistObject& sourceObject,
1174 const Kokkos::DualView<
const local_ordinal_type*,
1178 Kokkos::DualView<
size_t*,
1180 size_t& constantNumPackets)
1182 using Teuchos::Comm;
1186 const char prefix[] =
"Tpetra::Details::CooMatrix::packAndPrepare: ";
1187 const char suffix[] =
" This should never happen. "
1188 "Please report this bug to the Tpetra developers.";
1192 constantNumPackets = 0;
1194 const this_COO_type* src =
dynamic_cast<const this_COO_type*
> (&sourceObject);
1195 if (src ==
nullptr) {
1196 std::ostream& err = this->markLocalErrorAndGetStream ();
1197 err << prefix <<
"Input argument 'sourceObject' is not a CooMatrix."
1200 else if (* (src->localError_)) {
1201 std::ostream& err = this->markLocalErrorAndGetStream ();
1202 err << prefix <<
"The source (input) object of the Import or Export "
1203 "is already in an error state on this process."
1206 else if (* (this->localError_)) {
1207 std::ostream& err = this->markLocalErrorAndGetStream ();
1208 err << prefix <<
"The target (output, \"this\") object of the Import "
1209 "or Export is already in an error state on this process." << endl;
1214 if (* (this->localError_)) {
1219 auto numPacketsPerLID_tmp = numPacketsPerLID;
1220 numPacketsPerLID_tmp.sync_host ();
1221 numPacketsPerLID_tmp.modify_host ();
1228 const size_t numExports = exportLIDs.extent (0);
1229 if (numExports == 0) {
1233 RCP<const Comm<int> > comm = src->getMap ().is_null () ?
1234 Teuchos::null : src->getMap ()->getComm ();
1235 if (comm.is_null () || comm->getSize () == 1) {
1236 if (numExports != static_cast<size_t> (0)) {
1237 std::ostream& err = this->markLocalErrorAndGetStream ();
1238 err << prefix <<
"The input communicator is either null or "
1239 "has only one process, but numExports = " << numExports <<
" != 0."
1250 numPacketsPerLID.sync_host ();
1251 numPacketsPerLID.modify_host ();
1253 TEUCHOS_ASSERT( ! exportLIDs.need_sync_host () );
1254 auto exportLIDs_h = exportLIDs.view_host ();
1256 int totalNumPackets = 0;
1257 size_t numInvalidRowInds = 0;
1258 std::ostringstream errStrm;
1259 for (
size_t k = 0; k < numExports; ++k) {
1260 const LO lclRow = exportLIDs_h[k];
1263 const GO gblRow = src->map_->getGlobalElement (lclRow);
1264 if (gblRow == ::Tpetra::Details::OrdinalTraits<GO>::invalid ()) {
1266 ++numInvalidRowInds;
1267 numPacketsPerLID.h_view[k] = 0;
1275 src->impl_.countPackRow (numPackets, gblRow, *comm, &errStrm);
1277 std::ostream& err = this->markLocalErrorAndGetStream ();
1278 err << prefix << errStrm.str () << endl;
1279 numPacketsPerLID.h_view[k] = 0;
1285 const long long newTotalNumPackets =
1286 static_cast<long long> (totalNumPackets) +
1287 static_cast<long long> (numPackets);
1288 if (newTotalNumPackets >
1289 static_cast<long long> (std::numeric_limits<int>::max ())) {
1290 std::ostream& err = this->markLocalErrorAndGetStream ();
1291 err << prefix <<
"The new total number of packets "
1292 << newTotalNumPackets <<
" does not fit in int." << endl;
1296 for (
size_t k2 = k; k2 < numExports; ++k2) {
1297 numPacketsPerLID.h_view[k2] = 0;
1301 numPacketsPerLID.h_view[k] =
static_cast<size_t> (numPackets);
1302 totalNumPackets =
static_cast<int> (newTotalNumPackets);
1307 if (numInvalidRowInds != 0) {
1308 std::vector<std::pair<LO, GO> > invalidRowInds;
1309 for (
size_t k = 0; k < numExports; ++k) {
1310 const LO lclRow = exportLIDs_h[k];
1314 const GO gblRow = src->map_->getGlobalElement (lclRow);
1315 if (gblRow == ::Tpetra::Details::OrdinalTraits<GO>::invalid ()) {
1316 invalidRowInds.push_back ({lclRow, gblRow});
1319 std::ostringstream os;
1320 os << prefix <<
"We found " << numInvalidRowInds <<
" invalid row ind"
1321 << (numInvalidRowInds !=
static_cast<size_t> (1) ?
"ices" :
"ex")
1322 <<
" out of " << numExports <<
" in exportLIDs. Here is the list "
1323 <<
" of invalid row indices: [";
1324 for (
size_t k = 0; k < invalidRowInds.size (); ++k) {
1325 os <<
"(LID: " << invalidRowInds[k].first <<
", GID: "
1326 << invalidRowInds[k].second <<
")";
1327 if (k + 1 < invalidRowInds.size ()) {
1333 std::ostream& err = this->markLocalErrorAndGetStream ();
1334 err << prefix << os.str () << std::endl;
1339 const bool reallocated =
1341 "CooMatrix exports");
1343 exports.sync_host ();
1346 exports.modify_host ();
1350 std::vector<GO> gblRowInds;
1351 std::vector<GO> gblColInds;
1352 std::vector<SC> vals;
1354 int outBufCurPos = 0;
1356 for (
size_t k = 0; k < numExports; ++k) {
1357 const LO lclRow = exportLIDs.h_view[k];
1360 const GO gblRow = src->map_->getGlobalElement (lclRow);
1362 src->impl_.packRow (outBuf, totalNumPackets, outBufCurPos, *comm,
1363 gblRowInds, gblColInds, vals, gblRow);
1369 (
const Kokkos::DualView<
const local_ordinal_type*,
1373 Kokkos::DualView<
size_t*,
1378 using Teuchos::Comm;
1381 const char prefix[] =
"Tpetra::Details::CooMatrix::unpackAndCombine: ";
1382 const char suffix[] =
" This should never happen. "
1383 "Please report this bug to the Tpetra developers.";
1385 TEUCHOS_ASSERT( ! importLIDs.need_sync_host () );
1386 auto importLIDs_h = importLIDs.view_host ();
1388 const std::size_t numImports = importLIDs.extent (0);
1389 if (numImports == 0) {
1392 else if (imports.extent (0) == 0) {
1393 std::ostream& err = this->markLocalErrorAndGetStream ();
1394 err << prefix <<
"importLIDs.extent(0) = " << numImports <<
" != 0, "
1395 <<
"but imports.extent(0) = 0. This doesn't make sense, because "
1396 <<
"for every incoming LID, CooMatrix packs at least the count of "
1397 <<
"triples associated with that LID, even if the count is zero. "
1398 <<
"importLIDs = [";
1399 for (std::size_t k = 0; k < numImports; ++k) {
1400 err << importLIDs_h[k];
1401 if (k + 1 < numImports) {
1405 err <<
"]. " << suffix << endl;
1409 RCP<const Comm<int> > comm = this->
getMap ().is_null () ?
1410 Teuchos::null : this->
getMap ()->getComm ();
1411 if (comm.is_null () || comm->getSize () == 1) {
1412 if (numImports != static_cast<size_t> (0)) {
1413 std::ostream& err = this->markLocalErrorAndGetStream ();
1414 err << prefix <<
"The input communicator is either null or "
1415 "has only one process, but numImports = " << numImports <<
" != 0."
1428 if (static_cast<size_t> (imports.extent (0)) >
1429 static_cast<size_t> (std::numeric_limits<int>::max ())) {
1430 std::ostream& err = this->markLocalErrorAndGetStream ();
1431 err << prefix <<
"imports.extent(0) = "
1432 << imports.extent (0) <<
" does not fit in int." << endl;
1435 const int inBufSize =
static_cast<int> (imports.extent (0));
1437 if (imports.need_sync_host ()) {
1438 imports.sync_host ();
1440 if (numPacketsPerLID.need_sync_host ()) {
1441 numPacketsPerLID.sync_host ();
1443 auto imports_h = imports.view_host ();
1444 auto numPacketsPerLID_h = numPacketsPerLID.view_host ();
1448 std::vector<GO> gblRowInds;
1449 std::vector<GO> gblColInds;
1450 std::vector<SC> vals;
1453 int inBufCurPos = 0;
1454 size_t numInvalidRowInds = 0;
1456 std::ostringstream errStrm;
1457 for (
size_t k = 0; k < numImports; ++k) {
1458 const LO lclRow = importLIDs_h(k);
1459 const GO gblRow = this->
map_->getGlobalElement (lclRow);
1460 if (gblRow == ::Tpetra::Details::OrdinalTraits<GO>::invalid ()) {
1461 ++numInvalidRowInds;
1467 const int origInBufCurPos = inBufCurPos;
1471 numEnt, *comm, &errStrm);
1472 if (errCode != 0 || numEnt < 0 || inBufCurPos < origInBufCurPos) {
1473 std::ostream& err = this->markLocalErrorAndGetStream ();
1475 err << prefix <<
"In unpack loop, k=" << k <<
": ";
1477 err <<
" unpackTriplesCount returned errCode = " << errCode
1478 <<
" != 0." << endl;
1481 err <<
" unpackTriplesCount returned errCode = 0, but numEnt = "
1482 << numEnt <<
" < 0." << endl;
1484 if (inBufCurPos < origInBufCurPos) {
1485 err <<
" After unpackTriplesCount, inBufCurPos = " << inBufCurPos
1486 <<
" < origInBufCurPos = " << origInBufCurPos <<
"." << endl;
1488 err <<
" unpackTriplesCount report: " << errStrm.str () << endl;
1489 err << suffix << endl;
1496 #ifdef HAVE_TPETRA_DEBUG
1503 #endif // HAVE_TPETRA_DEBUG
1508 gblRowInds.resize (numEnt);
1509 gblColInds.resize (numEnt);
1510 vals.resize (numEnt);
1513 gblRowInds.data (), gblColInds.data (),
1514 vals.data (), numEnt, *comm, &errStrm);
1516 std::ostream& err = this->markLocalErrorAndGetStream ();
1517 err << prefix <<
"unpackTriples returned errCode = "
1518 << errCode <<
" != 0. It reports: " << errStrm.str ()
1525 #ifdef HAVE_TPETRA_DEBUG
1532 #endif // HAVE_TPETRA_DEBUG
1535 vals.data (), numEnt);
1540 if (numInvalidRowInds != 0) {
1544 std::ostream& err = this->markLocalErrorAndGetStream ();
1546 std::vector<std::pair<LO, GO> > invalidRowInds;
1547 for (
size_t k = 0; k < numImports; ++k) {
1548 const LO lclRow = importLIDs_h(k);
1549 const GO gblRow = this->
map_->getGlobalElement (lclRow);
1550 if (gblRow == ::Tpetra::Details::OrdinalTraits<GO>::invalid ()) {
1551 invalidRowInds.push_back ({lclRow, gblRow});
1555 err << prefix <<
"We found " << numInvalidRowInds <<
" invalid row ind"
1556 << (numInvalidRowInds !=
static_cast<size_t> (1) ?
"ices" :
"ex")
1557 <<
" out of " << numImports <<
" in importLIDs. Here is the list "
1558 <<
" of invalid row indices: [";
1559 for (
size_t k = 0; k < invalidRowInds.size (); ++k) {
1560 err <<
"(LID: " << invalidRowInds[k].first <<
", GID: "
1561 << invalidRowInds[k].second <<
")";
1562 if (k + 1 < invalidRowInds.size ()) {
1575 #endif // TPETRA_DETAILS_COOMATRIX_HPP
char packet_type
Type for packing and unpacking data.
int packTriplesCount(const int, char[], const int, int &, const ::Teuchos::Comm< int > &, std::ostream *errStrm)
Pack the count (number) of matrix triples.
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).
Node node_type
The Node type. If you don't know what this is, don't use it.
CooMatrixImpl()=default
Default constructor.
std::string errorMessages() const
The current stream of error messages.
Declaration of a function that prints strings from each 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...
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.
Function comparing two CooGraphEntry structs, lexicographically, first by row index, then by column index.
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...
Sparse matrix used only for file input / output.
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.
void fillComplete()
Special version of fillComplete that assumes that the matrix already has a Map, and reuses its commun...
GlobalOrdinal global_ordinal_type
The type of global indices.
virtual ~CooMatrix()
Destructor (virtual for memory safety of derived classes).
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, in rank order.
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 deep_copy(MultiVector< DS, DL, DG, DN > &dst, const MultiVector< SS, SL, SG, SN > &src)
Copy the contents of the MultiVector src into dst.
std::size_t getLclNumEntries() const
Number of entries in the sparse matrix on the calling process.
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...
Type of each (row index, column index) pair in the Tpetra::Details::CooMatrix (see below)...
bool localError() const
Whether this object had an error on the calling process.
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.
SC scalar_type
Type of each entry (value) in the sparse matrix.
CooMatrix()
Default constructor.
virtual size_t constantNumberOfPackets() const
By returning 0, tell DistObject that this class may not necessarily have a constant number of "packet...
void sumIntoGlobalValues(const GO gblRowInds[], const GO gblColInds[], const SC vals[], const std::size_t numEnt)
Insert multiple entries locally into the sparse matrix.
CooMatrix(const ::Teuchos::RCP< const map_type > &map)
Constructor that takes a Map.
virtual bool checkSizes(const ::Tpetra::SrcDistObject &source)
Compare the source and target (this) objects for compatibility.
void sumIntoGlobalValues(const GO gblRowInds[], const GO gblColInds[], const SC vals[], const std::size_t numEnt)
Insert multiple entries locally into the sparse matrix.
CombineMode
Rule for combining data in an Import or Export.
Teuchos::RCP< const map_type > map_
The Map over which this object is distributed.
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.
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")...
::Tpetra::Map< local_ordinal_type, global_ordinal_type, node_type > map_type
Type of the Map specialization to give to the constructor.
Declaration and definition of Tpetra::Details::reallocDualViewIfNeeded, an implementation detail of T...
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)...
LocalOrdinal local_ordinal_type
The type of local indices.
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...
std::size_t getLclNumEntries() const
Number of entries in the sparse matrix on the calling process.
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...
typename::Tpetra::DistObject< char, LO, GO, NT >::buffer_device_type buffer_device_type
Kokkos::Device specialization for DistObject communication buffers.
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.
char packet_type
This class transfers data as bytes (MPI_BYTE).
virtual std::string description() const
One-line descriptiion of this object; overrides Teuchos::Describable method.
virtual Teuchos::RCP< const map_type > getMap() const
The Map describing the parallel distribution of this object.
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.
Base class for distributed Tpetra objects that support data redistribution.
Implementation detail of Tpetra::Details::CooMatrix (which see below).
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.