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;
542 global_ordinal_type, node_type>
555 : base_type(::Teuchos::null)
556 , localError_(new bool(false))
557 , errs_(new std::shared_ptr<std::ostringstream>())
569 , localError_(new bool(false))
570 , errs_(new std::shared_ptr<std::ostringstream>())
599 const GO gblColInds[],
601 const std::size_t numEnt) {
608 std::initializer_list<GO> gblColInds,
609 std::initializer_list<SC> vals,
610 const std::size_t numEnt) {
612 vals.begin(), numEnt);
621 template <
class OffsetType>
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;
635 gblColInds = View<GO*, device_type>(
"gblColInds", numEnt);
636 vals = View<ISC*, device_type>(
"vals", numEnt);
637 auto gblColInds_h = create_mirror_view(gblColInds);
638 auto vals_h = create_mirror_view(vals);
640 std::vector<std::size_t> rowOffsetsSV;
641 this->impl_.buildCrs(rowOffsetsSV,
645 View<OffsetType*, device_type>(
"rowOffsets", rowOffsetsSV.size());
646 typename View<OffsetType*, device_type>::host_mirror_type
647 rowOffsets_h(rowOffsetsSV.data(), rowOffsetsSV.size());
665 fillComplete(const ::Teuchos::RCP<const ::Teuchos::Comm<int> >& comm) {
666 if (comm.is_null()) {
667 this->
map_ = ::Teuchos::null;
669 this->
map_ = this->buildMap(comm);
683 TEUCHOS_TEST_FOR_EXCEPTION(this->
getMap().is_null(), std::runtime_error,
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.");
727 return ((*errs_).get() == NULL) ? std::string(
"") : (*errs_)->str();
743 std::shared_ptr<bool> localError_;
752 std::shared_ptr<std::shared_ptr<std::ostringstream> > errs_;
756 markLocalErrorAndGetStream() {
757 *(this->localError_) =
true;
758 if ((*errs_).get() == NULL) {
759 *errs_ = std::shared_ptr<std::ostringstream>(
new std::ostringstream());
768 using Teuchos::TypeNameTraits;
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() <<
"\"";
779 os <<
", Has Map: " << (this->
map_.is_null() ?
"false" :
"true")
788 const Teuchos::EVerbosityLevel verbLevel =
789 Teuchos::Describable::verbLevel_default)
const {
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;
799 const auto vl = (verbLevel == VERB_DEFAULT) ? VERB_LOW : verbLevel;
801 auto comm = this->
getMap().is_null() ? Teuchos::null : this->
getMap()->getComm();
802 const int myRank = comm.is_null() ? 0 : comm->getRank();
805 if (vl != Teuchos::VERB_NONE) {
809 out <<
"\"Tpetra::Details::CooMatrix\":" << endl;
813 out <<
"Template parameters:" << endl;
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;
821 if (this->getObjectLabel() !=
"") {
822 out <<
"Label: \"" << this->getObjectLabel() <<
"\"" << endl;
824 out <<
"Has Map: " << (this->
map_.is_null() ?
"false" :
"true") << endl;
828 if (!this->
map_.is_null()) {
830 out <<
"Map:" << endl;
833 this->
map_->describe(out, vl);
838 std::ostringstream os;
839 os <<
"Process " << myRank <<
":" << endl;
843 os <<
" Local number of entries: " << numEnt << endl;
844 if (vl > VERB_MEDIUM) {
845 os <<
" Local entries:" << endl;
847 this->impl_.
forAllEntries([&os](
const GO row,
const GO col,
const SC& val) {
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;
879 if (comm.is_null()) {
880 return ::Teuchos::null;
891 std::vector<GO> rowInds;
895 GO gblMinGblRowInd = 0;
896 reduceAll<int, GO>(*comm, REDUCE_MIN, lclMinGblRowInd,
897 outArg(gblMinGblRowInd));
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(),
909 return static_cast<size_t>(0);
919 const char prefix[] =
"Tpetra::Details::CooMatrix::checkSizes: ";
921 const this_COO_type* src =
dynamic_cast<const this_COO_type*
>(&source);
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 "
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."
935 return !(*(this->localError_));
940 typename ::Tpetra::DistObject<char, LO, GO, NT>::buffer_device_type;
943 copyAndPermute(const ::Tpetra::SrcDistObject& sourceObject,
944 const size_t numSameIDs,
945 const Kokkos::DualView<
const LO*,
947 const Kokkos::DualView<
const LO*,
952 const char prefix[] =
"Tpetra::Details::CooMatrix::copyAndPermute: ";
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."
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."
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;
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;
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;
1004 const LO numSame =
static_cast<int>(numSameIDs);
1009 LO numInvalidSameRows = 0;
1010 for (LO lclRow = 0; lclRow < numSame; ++lclRow) {
1014 const GO gblRow = this->
map_->getGlobalElement(lclRow);
1015 if (gblRow == ::Tpetra::Details::OrdinalTraits<GO>::invalid()) {
1016 ++numInvalidSameRows;
1028 const LO numPermute =
static_cast<int>(numPermuteIDs);
1033 LO numInvalidRowsFrom = 0;
1038 LO numInvalidRowsTo = 0;
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();
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);
1051 bool bothConversionsValid =
true;
1052 if (gblRowFrom == ::Tpetra::Details::OrdinalTraits<GO>::invalid()) {
1053 ++numInvalidRowsFrom;
1054 bothConversionsValid =
false;
1056 if (gblRowTo == ::Tpetra::Details::OrdinalTraits<GO>::invalid()) {
1058 bothConversionsValid =
false;
1060 if (bothConversionsValid) {
1061 this->impl_.
mergeIntoRow(gblRowTo, src->impl_, gblRowFrom);
1066 if (numInvalidSameRows != 0 || numInvalidRowsFrom != 0 ||
1067 numInvalidRowsTo != 0) {
1070 std::vector<std::pair<LO, GO> > invalidSameRows;
1071 invalidSameRows.reserve(numInvalidSameRows);
1072 std::vector<std::pair<LO, GO> > invalidRowsFrom;
1073 invalidRowsFrom.reserve(numInvalidRowsFrom);
1074 std::vector<std::pair<LO, GO> > invalidRowsTo;
1075 invalidRowsTo.reserve(numInvalidRowsTo);
1077 for (LO lclRow = 0; lclRow < numSame; ++lclRow) {
1081 const GO gblRow = this->
map_->getGlobalElement(lclRow);
1082 if (gblRow == ::Tpetra::Details::OrdinalTraits<GO>::invalid()) {
1083 invalidSameRows.push_back({lclRow, gblRow});
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);
1093 if (gblRowFrom == ::Tpetra::Details::OrdinalTraits<GO>::invalid()) {
1094 invalidRowsFrom.push_back({lclRowFrom, gblRowFrom});
1096 if (gblRowTo == ::Tpetra::Details::OrdinalTraits<GO>::invalid()) {
1097 invalidRowsTo.push_back({lclRowTo, gblRowTo});
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()) {
1111 os <<
"]" << std::endl;
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()) {
1122 os <<
"]" << std::endl;
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()) {
1133 os <<
"]" << std::endl;
1136 std::ostream& err = this->markLocalErrorAndGetStream();
1137 err << prefix << os.str();
1143 packAndPrepare(const ::Tpetra::SrcDistObject& sourceObject,
1148 Kokkos::DualView<
size_t*,
1151 size_t& constantNumPackets) {
1153 using Teuchos::Comm;
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.";
1163 constantNumPackets = 0;
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."
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."
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."
1184 if (*(this->localError_)) {
1189 auto numPacketsPerLID_tmp = numPacketsPerLID;
1190 numPacketsPerLID_tmp.sync_host();
1191 numPacketsPerLID_tmp.modify_host();
1194 Kokkos::deep_copy(numPacketsPerLID.view_host(),
static_cast<size_t>(0));
1198 const size_t numExports = exportLIDs.extent(0);
1199 if (numExports == 0) {
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."
1220 numPacketsPerLID.sync_host();
1221 numPacketsPerLID.modify_host();
1223 TEUCHOS_ASSERT(!exportLIDs.need_sync_host());
1224 auto exportLIDs_h = exportLIDs.view_host();
1226 int totalNumPackets = 0;
1227 size_t numInvalidRowInds = 0;
1228 std::ostringstream errStrm;
1229 for (
size_t k = 0; k < numExports; ++k) {
1230 const LO lclRow = exportLIDs_h[k];
1233 const GO gblRow = src->
map_->getGlobalElement(lclRow);
1234 if (gblRow == ::Tpetra::Details::OrdinalTraits<GO>::invalid()) {
1236 ++numInvalidRowInds;
1237 numPacketsPerLID.view_host()[k] = 0;
1245 src->impl_.countPackRow(numPackets, gblRow, *comm, &errStrm);
1247 std::ostream& err = this->markLocalErrorAndGetStream();
1248 err << prefix << errStrm.str() << endl;
1249 numPacketsPerLID.view_host()[k] = 0;
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;
1266 for (
size_t k2 = k; k2 < numExports; ++k2) {
1267 numPacketsPerLID.view_host()[k2] = 0;
1271 numPacketsPerLID.view_host()[k] =
static_cast<size_t>(numPackets);
1272 totalNumPackets =
static_cast<int>(newTotalNumPackets);
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];
1284 const GO gblRow = src->
map_->getGlobalElement(lclRow);
1285 if (gblRow == ::Tpetra::Details::OrdinalTraits<GO>::invalid()) {
1286 invalidRowInds.push_back({lclRow, gblRow});
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()) {
1303 std::ostream& err = this->markLocalErrorAndGetStream();
1304 err << prefix << os.str() << std::endl;
1309 const bool reallocated =
1311 "CooMatrix exports");
1313 exports.sync_host();
1316 exports.modify_host();
1320 std::vector<GO> gblRowInds;
1321 std::vector<GO> gblColInds;
1322 std::vector<SC> vals;
1324 int outBufCurPos = 0;
1326 for (
size_t k = 0; k < numExports; ++k) {
1327 const LO lclRow = exportLIDs.view_host()[k];
1330 const GO gblRow = src->
map_->getGlobalElement(lclRow);
1332 src->impl_.packRow(outBuf, totalNumPackets, outBufCurPos, *comm,
1333 gblRowInds, gblColInds, vals, gblRow);
1338 unpackAndCombine(
const Kokkos::DualView<
const local_ordinal_type*,
1343 Kokkos::DualView<
size_t*,
1347 const ::Tpetra::CombineMode ) {
1349 using Teuchos::Comm;
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.";
1356 TEUCHOS_ASSERT(!importLIDs.need_sync_host());
1357 auto importLIDs_h = importLIDs.view_host();
1359 const std::size_t numImports = importLIDs.extent(0);
1360 if (numImports == 0) {
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) {
1375 err <<
"]. " << suffix << endl;
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."
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;
1405 const int inBufSize =
static_cast<int>(imports.extent(0));
1407 if (imports.need_sync_host()) {
1408 imports.sync_host();
1410 if (numPacketsPerLID.need_sync_host()) {
1411 numPacketsPerLID.sync_host();
1413 auto imports_h = imports.view_host();
1414 auto numPacketsPerLID_h = numPacketsPerLID.view_host();
1418 std::vector<GO> gblRowInds;
1419 std::vector<GO> gblColInds;
1420 std::vector<SC> vals;
1423 int inBufCurPos = 0;
1424 size_t numInvalidRowInds = 0;
1426 std::ostringstream errStrm;
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;
1437 const int origInBufCurPos = inBufCurPos;
1441 numEnt, *comm, &errStrm);
1442 if (errCode != 0 || numEnt < 0 || inBufCurPos < origInBufCurPos) {
1443 std::ostream& err = this->markLocalErrorAndGetStream();
1445 err << prefix <<
"In unpack loop, k=" << k <<
": ";
1447 err <<
" unpackTriplesCount returned errCode = " << errCode
1448 <<
" != 0." << endl;
1451 err <<
" unpackTriplesCount returned errCode = 0, but numEnt = "
1452 << numEnt <<
" < 0." << endl;
1454 if (inBufCurPos < origInBufCurPos) {
1455 err <<
" After unpackTriplesCount, inBufCurPos = " << inBufCurPos
1456 <<
" < origInBufCurPos = " << origInBufCurPos <<
"." << endl;
1458 err <<
" unpackTriplesCount report: " << errStrm.str() << endl;
1459 err << suffix << endl;
1466#ifdef HAVE_TPETRA_DEBUG
1478 gblRowInds.resize(numEnt);
1479 gblColInds.resize(numEnt);
1480 vals.resize(numEnt);
1483 gblRowInds.data(), gblColInds.data(),
1484 vals.data(), numEnt, *comm, &errStrm);
1486 std::ostream& err = this->markLocalErrorAndGetStream();
1487 err << prefix <<
"unpackTriples returned errCode = "
1488 << errCode <<
" != 0. It reports: " << errStrm.str()
1495#ifdef HAVE_TPETRA_DEBUG
1505 vals.data(), numEnt);
1510 if (numInvalidRowInds != 0) {
1514 std::ostream& err = this->markLocalErrorAndGetStream();
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});
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()) {