Tpetra parallel linear algebra Version of the Day
Loading...
Searching...
No Matches
Tpetra_Import_def.hpp
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_IMPORT_DEF_HPP
11#define TPETRA_IMPORT_DEF_HPP
12
13#include "Tpetra_Distributor.hpp"
14#include "Tpetra_Map.hpp"
15#include "Tpetra_ImportExportData.hpp"
16#include "Tpetra_Util.hpp"
18#include "Tpetra_Export.hpp"
20#include "Tpetra_Details_DualViewUtil.hpp"
23#include "Teuchos_as.hpp"
24#include <array>
25#include <memory>
26
27namespace Teuchos {
28template <class T>
29std::string toString(const std::vector<T>& x) {
30 std::ostringstream os;
31 os << "[";
32 const std::size_t N = x.size();
33 for (std::size_t k = 0; k < N; ++k) {
34 os << x[k];
35 if (k + std::size_t(1) < N) {
36 os << ",";
37 }
38 }
39 os << "]";
40 return os.str();
41}
42
43template <class ElementType, class DeviceType>
44std::string toString(const Kokkos::View<const ElementType*, DeviceType>& x) {
45 std::ostringstream os;
46 os << "[";
47 const std::size_t N = std::size_t(x.extent(0));
48 for (std::size_t k = 0; k < N; ++k) {
49 os << x[k];
50 if (k + std::size_t(1) < N) {
51 os << ",";
52 }
53 }
54 os << "]";
55 return os.str();
56}
57} // namespace Teuchos
58
59namespace Tpetra {
60
61// head: init(source, target, true, remotePIDs, Teuchos::null);
62
63template <class LocalOrdinal, class GlobalOrdinal, class Node>
64void Import<LocalOrdinal, GlobalOrdinal, Node>::
65 init(const Teuchos::RCP<const map_type>& source,
66 const Teuchos::RCP<const map_type>& /* target */,
67 bool useRemotePIDs,
68 Teuchos::Array<int>& remotePIDs,
69 const Teuchos::RCP<Teuchos::ParameterList>& plist) {
70 using std::endl;
71 using Teuchos::Array;
72 using Teuchos::null;
73 using Teuchos::Ptr;
74 using Teuchos::rcp;
75 using ::Tpetra::Details::ProfilingRegion;
76 ProfilingRegion regionImportInit("Tpetra::Import::init");
77
78 std::unique_ptr<std::string> verbPrefix;
79 if (this->verbose()) {
80 std::ostringstream os;
81 const int myRank = source->getComm()->getRank();
82 os << "Proc " << myRank << ": Tpetra::Import::init: ";
83 verbPrefix = std::unique_ptr<std::string>(new std::string(os.str()));
84 os << endl;
85 this->verboseOutputStream() << os.str();
86 }
87
88 Array<GlobalOrdinal> remoteGIDs;
89
90 {
91 Tpetra::Details::ProfilingRegion MM("Tpetra:iport_ctor:preIData");
92 if (this->verbose()) {
93 std::ostringstream os;
94 os << *verbPrefix << "Call setupSamePermuteRemote" << endl;
95 this->verboseOutputStream() << os.str();
96 }
97 setupSamePermuteRemote(remoteGIDs);
98 }
99 {
100 Tpetra::Details::ProfilingRegion MM2("Tpetra:iport_ctor:preSetupExport");
101 if (source->isDistributed()) {
102 if (this->verbose()) {
103 std::ostringstream os;
104 os << *verbPrefix << "Call setupExport" << endl;
105 this->verboseOutputStream() << os.str();
106 }
107 setupExport(remoteGIDs, useRemotePIDs, remotePIDs);
108 } else if (this->verbose()) {
109 std::ostringstream os;
110 os << *verbPrefix << "Source Map not distributed; skip setupExport"
111 << endl;
112 this->verboseOutputStream() << os.str();
113 }
114 }
115
116 TEUCHOS_ASSERT(!this->TransferData_->permuteFromLIDs_.need_sync_device());
117 TEUCHOS_ASSERT(!this->TransferData_->permuteFromLIDs_.need_sync_host());
118 TEUCHOS_ASSERT(!this->TransferData_->permuteToLIDs_.need_sync_device());
119 TEUCHOS_ASSERT(!this->TransferData_->permuteToLIDs_.need_sync_host());
120 TEUCHOS_ASSERT(!this->TransferData_->remoteLIDs_.need_sync_device());
121 TEUCHOS_ASSERT(!this->TransferData_->remoteLIDs_.need_sync_host());
122 TEUCHOS_ASSERT(!this->TransferData_->exportLIDs_.need_sync_device());
123 TEUCHOS_ASSERT(!this->TransferData_->exportLIDs_.need_sync_host());
124
125 this->detectRemoteExportLIDsContiguous();
126
127 if (this->verbose()) {
128 std::ostringstream os;
129 os << *verbPrefix << "Done!" << endl;
130 this->verboseOutputStream() << os.str();
131 }
132}
133
134template <class LocalOrdinal, class GlobalOrdinal, class Node>
136 Import(const Teuchos::RCP<const map_type>& source,
137 const Teuchos::RCP<const map_type>& target)
138 : base_type(source, target, Teuchos::null, Teuchos::null, "Import") {
139 Teuchos::Array<int> dummy;
140 init(source, target, false, dummy, Teuchos::null);
141}
142
143template <class LocalOrdinal, class GlobalOrdinal, class Node>
145 Import(const Teuchos::RCP<const map_type>& source,
146 const Teuchos::RCP<const map_type>& target,
147 const Teuchos::RCP<Teuchos::FancyOStream>& out)
148 : base_type(source, target, out, Teuchos::null, "Import") {
149 Teuchos::Array<int> dummy;
150 init(source, target, false, dummy, Teuchos::null);
151}
152
153template <class LocalOrdinal, class GlobalOrdinal, class Node>
155 Import(const Teuchos::RCP<const map_type>& source,
156 const Teuchos::RCP<const map_type>& target,
157 const Teuchos::RCP<Teuchos::ParameterList>& plist)
158 : base_type(source, target, Teuchos::null, plist, "Import") {
159 Teuchos::Array<int> dummy;
160 init(source, target, false, dummy, plist);
161}
162
163template <class LocalOrdinal, class GlobalOrdinal, class Node>
165 Import(const Teuchos::RCP<const map_type>& source,
166 const Teuchos::RCP<const map_type>& target,
167 const Teuchos::RCP<Teuchos::FancyOStream>& out,
168 const Teuchos::RCP<Teuchos::ParameterList>& plist)
169 : base_type(source, target, out, plist, "Import") {
170 Teuchos::Array<int> dummy;
171 init(source, target, false, dummy, plist);
172}
173
174template <class LocalOrdinal, class GlobalOrdinal, class Node>
176 Import(const Teuchos::RCP<const map_type>& source,
177 const Teuchos::RCP<const map_type>& target,
178 Teuchos::Array<int>& remotePIDs,
179 const Teuchos::RCP<Teuchos::ParameterList>& plist)
180 : base_type(source, target, Teuchos::null, plist, "Import") {
181 init(source, target, true, remotePIDs, plist);
182}
183
184template <class LocalOrdinal, class GlobalOrdinal, class Node>
188
189template <class LocalOrdinal, class GlobalOrdinal, class Node>
193
194// cblcbl
195// This is the "createExpert" version of the constructor to be used with pid/gid pairs obtained from
196// reverse communication
197template <class LocalOrdinal, class GlobalOrdinal, class Node>
199 Import(const Teuchos::RCP<const Map<LocalOrdinal, GlobalOrdinal, Node>>& source,
200 const Teuchos::RCP<const Map<LocalOrdinal, GlobalOrdinal, Node>>& target,
201 const Teuchos::ArrayView<int>& userRemotePIDs,
202 const Teuchos::ArrayView<const LocalOrdinal>& userExportLIDs,
203 const Teuchos::ArrayView<const int>& userExportPIDs,
204 const Teuchos::RCP<Teuchos::ParameterList>& plist,
205 const Teuchos::RCP<Teuchos::FancyOStream>& out)
206 : base_type(source, target, out, plist, "Import") {
207 using std::endl;
208 using Teuchos::arcp;
209 using Teuchos::Array;
210 using Teuchos::ArrayRCP;
211 using Teuchos::ArrayView;
212 using Teuchos::as;
213 using Teuchos::null;
214 using Teuchos::rcp;
215 using ::Tpetra::Details::makeDualViewFromArrayView;
216 using LO = LocalOrdinal;
217 using GO = GlobalOrdinal;
218 using size_type = Teuchos::Array<int>::size_type;
219
220 std::unique_ptr<std::string> prefix;
221 if (this->verbose()) {
222 auto comm = source.is_null() ? Teuchos::null : source->getComm();
223 const int myRank = comm.is_null() ? -1 : comm->getRank();
224 std::ostringstream os;
225 os << "Proc " << myRank << ": Tpetra::Import createExpert ctor: ";
226 prefix = std::unique_ptr<std::string>(new std::string(os.str()));
227 os << "Start" << endl;
228 this->verboseOutputStream() << os.str();
229 }
230
231 ArrayView<const GO> sourceGIDs = source->getLocalElementList();
232 ArrayView<const GO> targetGIDs = target->getLocalElementList();
233
235 if (this->verbose()) {
236 std::ostringstream os;
237 os << *prefix << "Call setupSamePermuteRemote" << endl;
238 this->verboseOutputStream() << os.str();
239 }
240 setupSamePermuteRemote(tRemoteGIDs);
241
242 if (this->verbose()) {
243 std::ostringstream os;
244 os << *prefix << "Sort & filter IDs" << endl;
245 this->verboseOutputStream() << os.str();
246 }
247
248 auto tRemoteLIDs = this->TransferData_->remoteLIDs_.view_host();
249 this->TransferData_->remoteLIDs_.modify_host();
250 Teuchos::Array<int> tRemotePIDs(userRemotePIDs);
251
252 if (this->verbose() && this->getNumRemoteIDs() > 0 && !source->isDistributed()) {
253 std::ostringstream os;
254 os << *prefix << "Target Map has remote LIDs but source Map is not "
255 "distributed. Importing to a submap of the target Map."
256 << endl;
257 this->verboseOutputStream() << os.str();
258 }
259 // FIXME (mfh 03 Feb 2019) I don't see this as "abuse"; it's
260 // perfectly valid Petra Object Model behavior.
261 TPETRA_ABUSE_WARNING(getNumRemoteIDs() > 0 && !source->isDistributed(),
262 std::runtime_error,
263 "::constructExpert: Target Map has remote LIDs but source Map "
264 "is not distributed. Importing to a submap of the target Map.");
266 size_t(tRemoteGIDs.size()) != size_t(tRemoteLIDs.extent(0)),
267 std::runtime_error,
268 "Import::Import createExpert version: "
269 "Size mismatch on userRemotePIDs, remoteGIDs, and remoteLIDs "
270 "Array's to sort3.");
271
272 sort3(tRemotePIDs.begin(),
273 tRemotePIDs.end(),
274 tRemoteGIDs.begin(),
275 tRemoteLIDs.data());
276
277 // Get rid of IDs that don't exist in SourceMap
278 size_type cnt = 0;
279 size_type indexIntoRemotePIDs = tRemotePIDs.size();
280 for (size_type i = 0; i < indexIntoRemotePIDs; ++i) {
281 if (tRemotePIDs[i] == -1) {
282 ++cnt;
283 }
284 }
285
286 if (cnt == 0) { // done modifying remoteLIDs_
287 this->TransferData_->remoteLIDs_.sync_device();
288 } else {
289 if (indexIntoRemotePIDs - cnt > 0) {
293 cnt = 0;
294
295 for (size_type j = 0; j < indexIntoRemotePIDs; ++j)
296 if (tRemotePIDs[j] != -1) {
299 newRemoteLIDs[cnt] = target->getLocalElement(tRemoteGIDs[j]);
300 ++cnt;
301 }
305 makeDualViewFromArrayView(this->TransferData_->remoteLIDs_,
306 newRemoteLIDs().getConst(),
307 "remoteLIDs");
308 } else { // valid RemoteIDs empty
310 tRemoteGIDs.clear();
311 tRemotePIDs.clear();
312 this->TransferData_->remoteLIDs_ = decltype(this->TransferData_->remoteLIDs_)();
313 }
314 }
315
316 this->TransferData_->exportPIDs_ = Teuchos::Array<int>(userExportPIDs);
317 makeDualViewFromArrayView(this->TransferData_->exportLIDs_,
318 userExportLIDs, "exportLIDs");
319
320 bool locallyComplete = true;
321 for (size_type i = 0; i < userExportPIDs.size() && locallyComplete; ++i) {
322 if (userExportPIDs[i] == -1) {
323 locallyComplete = false;
324 }
325 }
326 this->TransferData_->isLocallyComplete_ = locallyComplete;
327
328 if (this->verbose()) {
329 std::ostringstream os;
330 os << *prefix << "locallyComplete: "
331 << (locallyComplete ? "true" : "false")
332 << "; call createFromSendsAndRecvs" << endl;
333 this->verboseOutputStream() << os.str();
334 }
335 {
336 Tpetra::Details::ProfilingRegion MM3("Tpetra:iport_ctor:cFSAR ");
337 Distributor& distributor = this->TransferData_->distributor_;
338 distributor.createFromSendsAndRecvs(this->TransferData_->exportPIDs_, tRemotePIDs);
339 }
340
341 this->detectRemoteExportLIDsContiguous();
342
343 TEUCHOS_ASSERT(!this->TransferData_->permuteFromLIDs_.need_sync_device());
344 TEUCHOS_ASSERT(!this->TransferData_->permuteFromLIDs_.need_sync_host());
345 TEUCHOS_ASSERT(!this->TransferData_->permuteToLIDs_.need_sync_device());
346 TEUCHOS_ASSERT(!this->TransferData_->permuteToLIDs_.need_sync_host());
347 TEUCHOS_ASSERT(!this->TransferData_->remoteLIDs_.need_sync_device());
348 TEUCHOS_ASSERT(!this->TransferData_->remoteLIDs_.need_sync_host());
349 TEUCHOS_ASSERT(!this->TransferData_->exportLIDs_.need_sync_device());
350 TEUCHOS_ASSERT(!this->TransferData_->exportLIDs_.need_sync_host());
351}
352
353template <class LocalOrdinal, class GlobalOrdinal, class Node>
355 Import(const Teuchos::RCP<const map_type>& source,
356 const Teuchos::RCP<const map_type>& target,
357 const size_t numSameIDs,
358 Teuchos::Array<LocalOrdinal>& permuteToLIDs,
359 Teuchos::Array<LocalOrdinal>& permuteFromLIDs,
360 Teuchos::Array<LocalOrdinal>& remoteLIDs,
361 Teuchos::Array<LocalOrdinal>& exportLIDs,
362 Teuchos::Array<int>& exportPIDs,
364 const Teuchos::RCP<Teuchos::FancyOStream>& out,
365 const Teuchos::RCP<Teuchos::ParameterList>& plist)
366 : base_type(source, target, out, plist, "Import") {
367 using std::endl;
368 using ::Tpetra::Details::makeDualViewFromArrayView;
369
370 std::unique_ptr<std::string> prefix;
371 if (this->verbose()) {
372 auto comm = source.is_null() ? Teuchos::null : source->getComm();
373 const int myRank = comm.is_null() ? -1 : comm->getRank();
374 std::ostringstream os;
375 os << "Proc " << myRank << ": Tpetra::Import export ctor: ";
376 prefix = std::unique_ptr<std::string>(new std::string(os.str()));
377 os << "Start" << endl;
378 this->verboseOutputStream() << os.str();
379 }
380
381 bool locallyComplete = true;
382 for (Teuchos::Array<int>::size_type i = 0; i < exportPIDs.size(); ++i) {
383 if (exportPIDs[i] == -1) {
384 locallyComplete = false;
385 }
386 }
387 if (this->verbose()) {
388 std::ostringstream os;
389 os << *prefix << "numSameIDs: " << numSameIDs << ", locallyComplete: "
390 << (locallyComplete ? "true" : "false") << endl;
391 this->verboseOutputStream() << os.str();
392 }
393
394 this->TransferData_->isLocallyComplete_ = locallyComplete;
395 this->TransferData_->numSameIDs_ = numSameIDs;
396
397 makeDualViewFromArrayView(this->TransferData_->permuteToLIDs_,
398 permuteToLIDs().getConst(),
399 "permuteToLIDs");
400 TEUCHOS_ASSERT(size_t(this->TransferData_->permuteToLIDs_.extent(0)) ==
401 size_t(permuteToLIDs.size()));
402 makeDualViewFromArrayView(this->TransferData_->permuteFromLIDs_,
403 permuteFromLIDs().getConst(),
404 "permuteFromLIDs");
405 TEUCHOS_ASSERT(size_t(this->TransferData_->permuteFromLIDs_.extent(0)) ==
406 size_t(permuteFromLIDs.size()));
407 makeDualViewFromArrayView(this->TransferData_->remoteLIDs_,
408 remoteLIDs().getConst(),
409 "remoteLIDs");
410 TEUCHOS_ASSERT(size_t(this->TransferData_->remoteLIDs_.extent(0)) ==
411 size_t(remoteLIDs.size()));
412 makeDualViewFromArrayView(this->TransferData_->exportLIDs_,
413 exportLIDs().getConst(),
414 "exportLIDs");
415 TEUCHOS_ASSERT(size_t(this->TransferData_->exportLIDs_.extent(0)) ==
416 size_t(exportLIDs.size()));
417 this->TransferData_->exportPIDs_.swap(exportPIDs);
418 this->TransferData_->distributor_.swap(distributor);
419
420 this->detectRemoteExportLIDsContiguous();
421
422 TEUCHOS_ASSERT(!this->TransferData_->permuteFromLIDs_.need_sync_device());
423 TEUCHOS_ASSERT(!this->TransferData_->permuteFromLIDs_.need_sync_host());
424 TEUCHOS_ASSERT(!this->TransferData_->permuteToLIDs_.need_sync_device());
425 TEUCHOS_ASSERT(!this->TransferData_->permuteToLIDs_.need_sync_host());
426 TEUCHOS_ASSERT(!this->TransferData_->remoteLIDs_.need_sync_device());
427 TEUCHOS_ASSERT(!this->TransferData_->remoteLIDs_.need_sync_host());
428 TEUCHOS_ASSERT(!this->TransferData_->exportLIDs_.need_sync_device());
429 TEUCHOS_ASSERT(!this->TransferData_->exportLIDs_.need_sync_host());
430}
431
432namespace { // (anonymous)
433
434template <class LO, class GO, class NT>
435struct ImportLocalSetupResult {
436 Teuchos::RCP<const ::Tpetra::Map<LO, GO, NT>> targetMap;
437 LO numSameIDs;
438 // std::vector<LO> permuteToLIDs; // users aren't supposed to have permutes
439 // std::vector<LO> permuteFromLIDs; // users aren't suppoosed to have permutes
440 std::vector<GO> remoteGIDs;
441 std::vector<LO> remoteLIDs;
442 std::vector<int> remotePIDs;
443 LO numPermutes; // users aren't supposed to have permutes
444};
445
446template <class T>
447void printArray(std::ostream& out, const T x[], const std::size_t N) {
448 out << "[";
449 for (std::size_t k = 0; k < N; ++k) {
450 out << x[k];
451 if (k + 1 < N) {
452 out << ", ";
453 }
454 }
455 out << "]";
456}
457
458template <class LO, class GO, class NT>
459ImportLocalSetupResult<LO, GO, NT>
460setupSamePermuteRemoteFromUserGlobalIndexList(const ::Tpetra::Map<LO, GO, NT>& sourceMap,
461 const GO targetMapRemoteOrPermuteGlobalIndices[],
462 const int targetMapRemoteOrPermuteProcessRanks[],
463 const LO numTargetMapRemoteOrPermuteGlobalIndices,
464 const bool mayReorderTargetMapIndicesLocally,
465 Teuchos::FancyOStream* out, // only valid if verbose
466 const std::string* verboseHeader, // only valid if verbose
467 const bool verbose,
468 const bool debug) {
469 using std::endl;
470 const int myRank = sourceMap.getComm()->getRank();
471 ImportLocalSetupResult<LO, GO, NT> result;
472
473 if (verbose) {
474 std::ostringstream os;
475 os << *verboseHeader << "- Import::setupSPR w/ remote GIDs & PIDs: " << endl
476 << *verboseHeader << " Input GIDs: ";
477 printArray(os, targetMapRemoteOrPermuteGlobalIndices, numTargetMapRemoteOrPermuteGlobalIndices);
478 os << endl
479 << " Input PIDs: ";
480 printArray(os, targetMapRemoteOrPermuteProcessRanks, numTargetMapRemoteOrPermuteGlobalIndices);
481 os << endl;
482 *out << os.str();
483 }
484
485 // In debug mode, check whether any of the input GIDs are
486 // actually in the source Map on the calling process. That's an
487 // error, because it means duplicate GIDs on the calling
488 // process. Also check if any of the input PIDs are invalid.
489 if (debug) {
490 std::vector<GO> badGIDs;
491 std::vector<int> badPIDs;
492 const Teuchos::Comm<int>& comm = *(sourceMap.getComm());
493 const int numProcs = comm.getSize();
494
495 for (LO k = 0; k < numTargetMapRemoteOrPermuteGlobalIndices; ++k) {
496 const GO tgtGID = targetMapRemoteOrPermuteGlobalIndices[k];
497 if (sourceMap.isNodeGlobalElement(tgtGID)) {
498 badGIDs.push_back(tgtGID);
499 }
500 const int tgtPID = targetMapRemoteOrPermuteProcessRanks[k];
501 if (tgtPID < 0 || tgtPID >= numProcs) {
502 badPIDs.push_back(tgtPID);
503 }
504 }
505
506 std::array<int, 2> lclStatus{{badGIDs.size() == 0 ? 1 : 0,
507 badPIDs.size() == 0 ? 1 : 0}};
508 std::array<int, 2> gblStatus{{0, 0}}; // output argument
509 Teuchos::reduceAll<int, int>(comm, Teuchos::REDUCE_MIN, 2,
510 lclStatus.data(), gblStatus.data());
511 const bool good = gblStatus[0] == 1 && gblStatus[1] == 1;
512 // Don't actually print all the "bad" GIDs and/or PIDs unless
513 // in verbose mode, since there could be many of them.
514 if (verbose && gblStatus[0] != 1) {
515 std::ostringstream os;
516 os << *verboseHeader << "- Some input GIDs are already in the source Map: ";
517 printArray(os, badGIDs.data(), badGIDs.size());
518 os << endl;
519 ::Tpetra::Details::gathervPrint(*out, os.str(), comm);
520 }
521 if (verbose && gblStatus[0] != 1) {
522 std::ostringstream os;
523 os << *verboseHeader << "- Some input PIDs are invalid: ";
524 printArray(os, badPIDs.data(), badPIDs.size());
525 os << endl;
526 ::Tpetra::Details::gathervPrint(*out, os.str(), comm);
527 }
528
529 if (!good) {
530 std::ostringstream os;
531 os << "Tpetra::Import constructor that takes remote GIDs and PIDs: ";
532 if (gblStatus[0] != 1) {
533 os << "Some input GIDs (global indices) are already in the source Map! ";
534 }
535 if (gblStatus[1] != 1) {
536 os << "Some input PIDs (process ranks) are invalid! ";
537 }
538 os << "Rerun with the environment variable TPETRA_VERBOSE=Tpetra::Import "
539 "to see what GIDs and/or PIDs are bad.";
540 TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument, os.str());
541 }
542 }
543
544 // Create list of GIDs to go into target Map. We need to copy
545 // the GIDs into this list anyway, so once we have them, we can
546 // sort the "remotes" in place.
547 const LO numLclSrcIDs = static_cast<LO>(sourceMap.getLocalNumElements());
548 const LO numLclTgtIDs = numLclSrcIDs + numTargetMapRemoteOrPermuteGlobalIndices;
549 if (verbose) {
550 std::ostringstream os;
551 os << *verboseHeader << "- Copy source Map GIDs into target Map GID list: "
552 "numLclSrcIDs="
553 << numLclSrcIDs
554 << ", numTargetMapRemoteOrPermuteGlobalIndices="
555 << numTargetMapRemoteOrPermuteGlobalIndices << endl;
556 *out << os.str();
557 }
558 std::vector<GO> tgtGIDs(numLclTgtIDs); // will go into target Map ctor
559 if (sourceMap.isContiguous()) {
560 GO curTgtGID = sourceMap.getMinGlobalIndex();
561 for (LO k = 0; k < numLclSrcIDs; ++k, ++curTgtGID) {
562 tgtGIDs[k] = curTgtGID;
563 }
564 } else { // avoid calling getLocalElementList on a contiguous Map
565 auto srcGIDs = sourceMap.getLocalElementList(); // Teuchos::ArrayView has a different
566 for (LO k = 0; k < numLclSrcIDs; ++k) { // iterator type, so can't std::copy
567 tgtGIDs[k] = srcGIDs[k];
568 }
569 }
570 std::copy(targetMapRemoteOrPermuteGlobalIndices,
571 targetMapRemoteOrPermuteGlobalIndices + numTargetMapRemoteOrPermuteGlobalIndices,
572 tgtGIDs.begin() + numLclSrcIDs);
573
574 // Optionally, sort input by process rank, so that remotes
575 // coming from the same process are grouped together. Only sort
576 // remote GIDs. While doing so, detect permutes (input "remote"
577 // GIDs whose rank is the same as that of the calling process).
578 //
579 // Permutes are actually an error. We normally detect them in
580 // debug mode, but if we sort, we have a nearly free opportunity
581 // to do so. We may also safely ignore permutes as duplicates.
582 //
583 // NOTE: tgtPIDs only includes remotes, not source Map entries.
584 if (verbose) {
585 std::ostringstream os;
586 os << *verboseHeader << "- Sort by PID? "
587 << (mayReorderTargetMapIndicesLocally ? "true" : "false") << endl;
588 *out << os.str();
589 }
590 std::vector<int> tgtPIDs(targetMapRemoteOrPermuteProcessRanks,
591 targetMapRemoteOrPermuteProcessRanks + numTargetMapRemoteOrPermuteGlobalIndices);
592 result.numPermutes = 0;
593 if (mayReorderTargetMapIndicesLocally) {
594 Tpetra::sort2(tgtPIDs.begin(), tgtPIDs.end(), tgtGIDs.begin() + numLclSrcIDs);
595 auto range = std::equal_range(tgtPIDs.begin(), tgtPIDs.end(), myRank); // binary search
596 if (range.second > range.first) {
597 result.numPermutes = static_cast<LO>(range.second - range.first);
598 }
599 } else { // don't sort; linear search to count permutes
600 result.numPermutes = static_cast<LO>(std::count(tgtPIDs.begin(), tgtPIDs.end(), myRank));
601 }
602 // The _actual_ number of remotes.
603 const LO numRemotes = numTargetMapRemoteOrPermuteGlobalIndices - result.numPermutes;
604 result.numSameIDs = static_cast<LO>(sourceMap.getLocalNumElements());
605
606 if (verbose) {
607 std::ostringstream os;
608 os << *verboseHeader << "- numSame=" << result.numSameIDs
609 << ", numPermutes=" << result.numPermutes
610 << ", numRemotes=" << numRemotes << endl;
611 *out << os.str();
612 }
613
614 if (result.numPermutes == 0) {
615 if (verbose) {
616 std::ostringstream os;
617 os << *verboseHeader << "- No permutes" << endl;
618 *out << os.str();
619 }
620 result.remoteGIDs = std::vector<GO>(tgtGIDs.begin() + numLclSrcIDs, tgtGIDs.end());
621 result.remotePIDs.swap(tgtPIDs);
622 result.remoteLIDs.resize(numRemotes);
623 for (LO k = 0; k < numRemotes; ++k) {
624 const LO tgtLid = result.numSameIDs + k;
625 result.remoteLIDs[k] = tgtLid;
626 }
627 if (verbose) {
628 std::ostringstream os;
629 os << *verboseHeader << "- Remote GIDs: "
630 << Teuchos::toString(result.remoteGIDs) << endl;
631 os << *verboseHeader << "- Remote PIDs: "
632 << Teuchos::toString(result.remotePIDs) << endl;
633 os << *verboseHeader << "- Remote LIDs: "
634 << Teuchos::toString(result.remoteLIDs) << endl;
635 *out << os.str();
636 }
637 } else { // separate permutes from remotes
638 // This case doesn't need to be optimal; it just needs to be
639 // correct. Users really shouldn't give permutes to this
640 // Import constructor.
641 result.remoteGIDs.reserve(numRemotes);
642 result.remoteLIDs.reserve(numRemotes);
643 result.remotePIDs.reserve(numRemotes);
644 for (LO k = 0; k < numTargetMapRemoteOrPermuteGlobalIndices; ++k) {
645 const LO tgtLid = result.numSameIDs + k;
646 const GO tgtGid = tgtGIDs[numLclSrcIDs + k];
647 const int tgtPid = tgtPIDs[k];
648
649 if (tgtPid != myRank) { // it's a remote
650 result.remoteGIDs.push_back(tgtGid);
651 result.remoteLIDs.push_back(tgtLid);
652 result.remotePIDs.push_back(tgtPid);
653 }
654 }
655 if (verbose) {
656 std::ostringstream os;
657 os << *verboseHeader << "- Some permutes" << endl;
658 *out << os.str();
659 }
660 }
661
662 if (sourceMap.isDistributed()) {
663 if (verbose) {
664 std::ostringstream os;
665 os << *verboseHeader << "- Sort remotes by PID, as Import always does"
666 << endl
667 << *verboseHeader << "-- remotePIDs before: "
668 << Teuchos::toString(result.remotePIDs) << endl
669 << *verboseHeader << "-- remoteGIDs before: "
670 << Teuchos::toString(result.remoteGIDs) << endl
671 << *verboseHeader << "-- remoteLIDs before: "
672 << Teuchos::toString(result.remoteLIDs) << endl;
673 *out << os.str();
674 }
675 // Import always sorts these, regardless of what the user wanted.
676 sort3(result.remotePIDs.begin(),
677 result.remotePIDs.end(),
678 result.remoteGIDs.begin(),
679 result.remoteLIDs.begin());
680 if (verbose) {
681 std::ostringstream os;
682 os << *verboseHeader << "-- remotePIDs after: "
683 << Teuchos::toString(result.remotePIDs) << endl
684 << *verboseHeader << "-- remoteGIDs after: "
685 << Teuchos::toString(result.remoteGIDs) << endl
686 << *verboseHeader << "-- remoteLIDs after: "
687 << Teuchos::toString(result.remoteLIDs) << endl;
688 std::cerr << os.str();
689 }
690 }
691
692 if (verbose) {
693 std::ostringstream os;
694 os << *verboseHeader << "- Make target Map" << endl;
695 *out << os.str();
696 }
697 using ::Teuchos::rcp;
698 typedef ::Tpetra::Map<LO, GO, NT> map_type;
699 typedef ::Tpetra::global_size_t GST;
700 const GST MAP_COMPUTES_GLOBAL_COUNT = ::Teuchos::OrdinalTraits<GST>::invalid();
701 result.targetMap = rcp(new map_type(MAP_COMPUTES_GLOBAL_COUNT,
702 tgtGIDs.data(),
703 numLclTgtIDs,
704 sourceMap.getIndexBase(),
705 sourceMap.getComm()));
706 if (verbose) {
707 std::ostringstream os;
708 os << *verboseHeader << "- Done with sameSPR..." << endl;
709 *out << os.str();
710 }
711 return result;
712}
713} // namespace
714
715template <class LocalOrdinal, class GlobalOrdinal, class Node>
722 const Teuchos::RCP<Teuchos::ParameterList>& plist,
723 const Teuchos::RCP<Teuchos::FancyOStream>& debugOutput)
724 : // Special case: target Map is null on base_type construction.
725 // It's worthwhile for invariants like out_ not being null.
726 // We'll set TransferData_ again below.
727 base_type(sourceMap, Teuchos::null, debugOutput, plist, "Import") {
728 using std::endl;
729 using Teuchos::ArrayView;
730 using Teuchos::getFancyOStream;
731 using Teuchos::RCP;
732 using Teuchos::rcp;
733 using Teuchos::rcpFromRef;
734 using ::Tpetra::Details::Behavior;
735 using ::Tpetra::Details::makeDualViewFromOwningHostView;
736 using ::Tpetra::Details::makeDualViewFromVector;
737 using ::Tpetra::Details::printDualView;
738 using ::Tpetra::Details::view_alloc_no_init;
739 typedef LocalOrdinal LO;
740 typedef GlobalOrdinal GO;
741 typedef Node NT;
742
743 const bool debug = Behavior::debug("Import") ||
744 Behavior::debug("Tpetra::Import");
745
746 std::unique_ptr<std::string> verbPfx;
747 if (this->verbose()) {
748 std::ostringstream os;
749 const int myRank = sourceMap->getComm()->getRank();
750 os << "Proc " << myRank << ": Tpetra::Import ctor from remotes: ";
751 verbPfx = std::unique_ptr<std::string>(new std::string(os.str()));
752 os << "mayReorder=" << (mayReorderTargetMapIndicesLocally ? "true" : "false")
753 << endl;
754 this->verboseOutputStream() << os.str();
755 }
756
757 TEUCHOS_ASSERT(!this->TransferData_.is_null());
764 this->TransferData_->out_.getRawPtr(),
765 verbPfx.get(),
766 this->verbose(),
767 debug);
768
769 // Since we invoked the base_type constructor above, we know that
770 // out_ is nonnull, so we don't have to waste time creating it
771 // again.
773 TEUCHOS_ASSERT(!this->TransferData_.is_null());
775 localSetupResult.targetMap,
776 this->TransferData_->out_,
777 plist));
778 this->TransferData_->numSameIDs_ = localSetupResult.numSameIDs;
779 // Skip permutes; they are user error, because they duplicate
780 // non-remote indices.
781 makeDualViewFromVector(this->TransferData_->remoteLIDs_,
782 localSetupResult.remoteLIDs,
783 "remoteLIDs");
784 // "Is locally complete" for an Import means that all target Map
785 // indices on the calling process exist on at least one process
786 // (not necessarily this one) in the source Map. For this
787 // constructor, this is true if and only if all input target PIDs
788 // are valid PIDs in the communicator.
789 //
790 // FIXME (mfh 20 Feb 2018) For now, assume this is always true.
791 this->TransferData_->isLocallyComplete_ = true;
792
793 Teuchos::Array<GO> exportGIDs;
794 if (sourceMap->isDistributed()) {
795 if (this->verbose()) {
796 std::ostringstream os;
797 os << *verbPfx << "Make Distributor (createFromRecvs)" << endl;
798 this->verboseOutputStream() << os.str();
799 }
800 ArrayView<const GO> remoteGIDs(localSetupResult.remoteGIDs.data(),
801 localSetupResult.remoteGIDs.size());
802 ArrayView<const int> remotePIDs(localSetupResult.remotePIDs.data(),
803 localSetupResult.remotePIDs.size());
804 // Call Distributor::createFromRecvs to turn the remote GIDs and
805 // their owning PIDs into a send-and-receive communication plan.
806 // remoteGIDs and remotePIDs are input; exportGIDs and
807 // exportPIDs are output arrays that createFromRecvs allocates.
808 Distributor& distributor = this->TransferData_->distributor_;
809 distributor.createFromRecvs(remoteGIDs,
810 remotePIDs,
812 this->TransferData_->exportPIDs_);
813 // Find the LIDs corresponding to the (outgoing) GIDs in
814 // exportGIDs. For sparse matrix-vector multiply, this tells
815 // the calling process how to index into the source vector to
816 // get the elements which it needs to send.
817 //
818 // NOTE (mfh 03 Mar 2014) This is now a candidate for a
819 // thread-parallel kernel, but only if using the new thread-safe
820 // Map implementation.
821 if (this->verbose()) {
822 std::ostringstream os;
823 os << *verbPfx << "Compute exportLIDs" << endl;
824 this->verboseOutputStream() << os.str();
825 }
826 using size_type = typename Teuchos::Array<GO>::size_type;
827 const size_type numExportIDs = exportGIDs.size();
828
829 typename decltype(this->TransferData_->exportLIDs_)::t_host
830 exportLIDs(view_alloc_no_init("exportLIDs"), numExportIDs);
831
832 for (size_type k = 0; k < numExportIDs; ++k) {
833 exportLIDs[k] = sourceMap->getLocalElement(exportGIDs[k]);
834 }
835 makeDualViewFromOwningHostView(this->TransferData_->exportLIDs_, exportLIDs);
836 }
837
838 if (this->verbose()) {
839 std::ostringstream os;
840 os << *verbPfx;
841 printDualView(os, this->TransferData_->remoteLIDs_,
842 "ImportExportData::remoteLIDs_");
843 os << endl;
844 this->verboseOutputStream() << os.str();
845 }
846 if (this->verbose()) {
847 std::ostringstream os;
848 os << *verbPfx << "Done!" << endl;
849 this->verboseOutputStream() << os.str();
850 }
851}
852
853template <class LocalOrdinal, class GlobalOrdinal, class Node>
855 describe(Teuchos::FancyOStream& out,
856 const Teuchos::EVerbosityLevel verbLevel) const {
857 // Call the base class' method. It does all the work.
858 this->describeImpl(out, "Tpetra::Import", verbLevel);
859}
860
861template <class LocalOrdinal, class GlobalOrdinal, class Node>
863 print(std::ostream& os) const {
864 auto out = Teuchos::getFancyOStream(Teuchos::rcpFromRef(os));
865 // "Print" traditionally meant "everything."
866 this->describe(*out, Teuchos::VERB_EXTREME);
867}
868
869template <class LocalOrdinal, class GlobalOrdinal, class Node>
871 setupSamePermuteRemote(Teuchos::Array<GlobalOrdinal>& remoteGIDs) {
872 using Teuchos::arcp;
873 using Teuchos::Array;
874 using Teuchos::ArrayRCP;
875 using Teuchos::ArrayView;
876 using Teuchos::as;
877 using Teuchos::null;
878 using ::Tpetra::Details::makeDualViewFromOwningHostView;
879 using ::Tpetra::Details::ProfilingRegion;
880 using ::Tpetra::Details::view_alloc_no_init;
881 typedef LocalOrdinal LO;
882 typedef GlobalOrdinal GO;
883 typedef typename ArrayView<const GO>::size_type size_type;
884 ProfilingRegion regionExport("Tpetra::Import::setupSamePermuteRemote");
885
886 const map_type& source = *(this->getSourceMap());
887 const map_type& target = *(this->getTargetMap());
888 ArrayView<const GO> sourceGIDs = source.getLocalElementList();
889 ArrayView<const GO> targetGIDs = target.getLocalElementList();
890
891#ifdef HAVE_TPETRA_DEBUG
894#else
895 const GO* const rawSrcGids = sourceGIDs.getRawPtr();
896 const GO* const rawTgtGids = targetGIDs.getRawPtr();
897#endif // HAVE_TPETRA_DEBUG
898 const size_type numSrcGids = sourceGIDs.size();
899 const size_type numTgtGids = targetGIDs.size();
900 const size_type numGids = std::min(numSrcGids, numTgtGids);
901
902 // Compute numSameIDs_: the number of initial GIDs that are the
903 // same (and occur in the same order) in both Maps. The point of
904 // numSameIDs_ is for the common case of an Import where all the
905 // overlapping GIDs are at the end of the target Map, but
906 // otherwise the source and target Maps are the same. This allows
907 // a fast contiguous copy for the initial "same IDs."
908 size_type numSameGids = 0;
910 } // third clause of 'for' does everything
911 this->TransferData_->numSameIDs_ = numSameGids;
912
913 // Compute permuteToLIDs_, permuteFromLIDs_, remoteGIDs, and
914 // remoteLIDs_. The first two arrays are IDs to be permuted, and
915 // the latter two arrays are IDs to be received ("imported"),
916 // called "remote" IDs.
917 //
918 // IDs to permute are in both the source and target Maps, which
919 // means we don't have to send or receive them, but we do have to
920 // rearrange (permute) them in general. IDs to receive are in the
921 // target Map, but not the source Map.
922
923 // Iterate over the target Map's LIDs, since we only need to do
924 // GID -> LID lookups for the source Map.
925 const LO LINVALID = Teuchos::OrdinalTraits<LO>::invalid();
926 const LO numTgtLids = as<LO>(numTgtGids);
927 LO numPermutes = 0;
928
929 for (LO tgtLid = numSameGids; tgtLid < numTgtLids; ++tgtLid) {
930 const GO curTargetGid = rawTgtGids[tgtLid];
931 // getLocalElement() returns LINVALID if the GID isn't in the
932 // source Map. This saves us a lookup (which
933 // isNodeGlobalElement() would do).
934 const LO srcLid = source.getLocalElement(curTargetGid);
935 if (srcLid != LINVALID) { // if source.isNodeGlobalElement (curTargetGid)
936 ++numPermutes;
937 }
938 }
939 const LO numRemotes = (numTgtLids - numSameGids) - numPermutes;
940
941 using host_perm_type =
942 typename decltype(this->TransferData_->permuteToLIDs_)::t_host;
943 host_perm_type permuteToLIDs(view_alloc_no_init("permuteToLIDs"), numPermutes);
944 host_perm_type permuteFromLIDs(view_alloc_no_init("permuteFromLIDs"), numPermutes);
945 typename decltype(this->TransferData_->remoteLIDs_)::t_host remoteLIDs(view_alloc_no_init("permuteFromLIDs"), numRemotes);
946
947 {
948 LO numPermutes2 = 0;
949 LO numRemotes2 = 0;
950 for (LO tgtLid = numSameGids; tgtLid < numTgtLids; ++tgtLid) {
951 const GO curTargetGid = rawTgtGids[tgtLid];
952 const LO srcLid = source.getLocalElement(curTargetGid);
953 if (srcLid != LINVALID) {
954 permuteToLIDs[numPermutes2] = tgtLid;
955 permuteFromLIDs[numPermutes2] = srcLid;
956 ++numPermutes2;
957 } else {
958 remoteGIDs.push_back(curTargetGid);
959 remoteLIDs[numRemotes2] = tgtLid;
960 ++numRemotes2;
961 }
962 }
963 TEUCHOS_ASSERT(numPermutes == numPermutes2);
964 TEUCHOS_ASSERT(numRemotes == numRemotes2);
965 TEUCHOS_ASSERT(size_t(numPermutes) + remoteGIDs.size() == size_t(numTgtLids - numSameGids));
966 }
967
968 makeDualViewFromOwningHostView(this->TransferData_->permuteToLIDs_, permuteToLIDs);
969 makeDualViewFromOwningHostView(this->TransferData_->permuteFromLIDs_, permuteFromLIDs);
970 makeDualViewFromOwningHostView(this->TransferData_->remoteLIDs_, remoteLIDs);
971 if (remoteLIDs.extent(0) != 0 && !source.isDistributed()) {
972 // This Import has remote LIDs, meaning that the target Map has
973 // entries on this process that are not in the source Map on
974 // this process. However, the source Map is not distributed
975 // globally. This implies that this Import is not locally
976 // complete on this process.
977 this->TransferData_->isLocallyComplete_ = false;
978 // mfh 12 Sep 2016: I disagree that this is "abuse"; it may be
979 // correct behavior, depending on the circumstances.
980 TPETRA_ABUSE_WARNING(true, std::runtime_error,
981 "::setupSamePermuteRemote(): Target has "
982 "remote LIDs but Source is not distributed globally. Importing to a "
983 "submap of the target map.");
984 }
985}
986
987template <class LocalOrdinal, class GlobalOrdinal, class Node>
988void Import<LocalOrdinal, GlobalOrdinal, Node>::
989 setupExport(Teuchos::Array<GlobalOrdinal>& remoteGIDs,
990 bool useRemotePIDs,
991 Teuchos::Array<int>& userRemotePIDs,
992 const Teuchos::RCP<Teuchos::ParameterList>& plist) {
993 using std::endl;
994 using Teuchos::Array;
995 using Teuchos::ArrayView;
996 using ::Tpetra::Details::makeDualViewFromOwningHostView;
997 using ::Tpetra::Details::view_alloc_no_init;
998 using GO = GlobalOrdinal;
999 typedef typename Array<int>::difference_type size_type;
1000 const char tfecfFuncName[] = "setupExport: ";
1001 const char suffix[] = " Please report this bug to the Tpetra developers.";
1002
1003 std::unique_ptr<std::string> prefix;
1004 if (this->verbose()) {
1005 auto srcMap = this->getSourceMap();
1006 auto comm = srcMap.is_null() ? Teuchos::null : srcMap->getComm();
1007 const int myRank = comm.is_null() ? -1 : comm->getRank();
1008 std::ostringstream os;
1009 os << "Proc " << myRank << ": Tpetra::Import::setupExport: ";
1010 prefix = std::unique_ptr<std::string>(new std::string(os.str()));
1011 os << "Start" << std::endl;
1012 this->verboseOutputStream() << os.str();
1013 }
1014
1015 TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC(this->getSourceMap().is_null(), std::logic_error,
1016 "Source Map is null. " << suffix);
1017 const map_type& source = *(this->getSourceMap());
1018
1019 TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC(!useRemotePIDs && (userRemotePIDs.size() > 0), std::invalid_argument,
1020 "remotePIDs are non-empty but their use has not been requested.");
1021 TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC(userRemotePIDs.size() > 0 && remoteGIDs.size() != userRemotePIDs.size(),
1022 std::invalid_argument,
1023 "remotePIDs must either be of size zero or match "
1024 "the size of remoteGIDs.");
1025
1026 // For each entry remoteGIDs[i], remoteProcIDs[i] will contain
1027 // the process ID of the process that owns that GID.
1028 ArrayView<GO> remoteGIDsView = remoteGIDs();
1029 ArrayView<int> remoteProcIDsView;
1030
1031 // lookup == IDNotPresent means that the source Map wasn't able to
1032 // figure out to which processes one or more of the GIDs in the
1033 // given list of remote GIDs belong.
1034 //
1035 // The previous abuse warning said "The target Map has GIDs not
1036 // found in the source Map." This statement could be confusing,
1037 // because it doesn't refer to ownership by the current process,
1038 // but rather to ownership by _any_ process participating in the
1039 // Map. (It could not possibly refer to ownership by the current
1040 // process, since remoteGIDs is exactly the list of GIDs owned by
1041 // the target Map but not owned by the source Map. It was
1042 // constructed that way by setupSamePermuteRemote().)
1043 //
1044 // What this statement means is that the source and target Maps
1045 // don't contain the same set of GIDs globally (over all
1046 // processes). That is, there is at least one GID owned by some
1047 // process in the target Map, which is not owned by _any_ process
1048 // in the source Map.
1049 Array<int> newRemotePIDs;
1050 LookupStatus lookup = AllIDsPresent;
1051
1052 if (!useRemotePIDs) {
1053 newRemotePIDs.resize(remoteGIDsView.size());
1054 if (this->verbose()) {
1055 std::ostringstream os;
1056 os << *prefix << "Call sourceMap.getRemoteIndexList" << endl;
1057 this->verboseOutputStream() << os.str();
1058 }
1059 lookup = source.getRemoteIndexList(remoteGIDsView, newRemotePIDs());
1060 }
1061 Array<int>& remoteProcIDs = useRemotePIDs ? userRemotePIDs : newRemotePIDs;
1062
1063 if (lookup == IDNotPresent) {
1064 // There is at least one GID owned by the calling process in the
1065 // target Map, which is not owned by any process in the source
1066 // Map.
1067 this->TransferData_->isLocallyComplete_ = false;
1068
1069 // mfh 12 Sep 2016: I disagree that this is "abuse"; it may be
1070 // correct behavior, depending on the circumstances.
1071 TPETRA_ABUSE_WARNING(true, std::runtime_error,
1072 "::setupExport(): the source Map wasn't "
1073 "able to figure out which process owns one or more of the GIDs in the "
1074 "list of remote GIDs. This probably means that there is at least one "
1075 "GID owned by some process in the target Map which is not owned by any"
1076 " process in the source Map. (That is, the source and target Maps do "
1077 "not contain the same set of GIDs globally.)");
1078
1079 // Ignore remote GIDs that aren't owned by any process in the
1080 // source Map. getRemoteIndexList() gives each of these a
1081 // process ID of -1.
1082
1083 const size_type numInvalidRemote =
1084 std::count_if(remoteProcIDs.begin(), remoteProcIDs.end(),
1085 std::bind(std::equal_to<int>(), -1, std::placeholders::_1));
1086 TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC(numInvalidRemote == 0, std::logic_error,
1087 "Calling getRemoteIndexList "
1088 "on the source Map returned IDNotPresent, but none of the returned "
1089 "\"remote\" process ranks are -1. Please report this bug to the "
1090 "Tpetra developers.");
1091
1092 auto MM = Teuchos::rcp(new Tpetra::Details::ProfilingRegion("Tpetra:iport_ctor:setupExport:1"));
1093
1094 // If all of them are invalid, we can delete the whole array.
1095 const size_type totalNumRemote = this->getNumRemoteIDs();
1096 if (numInvalidRemote == totalNumRemote) {
1097 // all remotes are invalid; we have no remotes; we can delete the remotes
1098 remoteProcIDs.clear();
1099 remoteGIDs.clear(); // invalidates remoteGIDsView
1100 this->TransferData_->remoteLIDs_ =
1101 decltype(this->TransferData_->remoteLIDs_)();
1102 } else {
1103 // Some remotes are valid; we need to keep the valid ones.
1104 // Pack and resize remoteProcIDs, remoteGIDs, and remoteLIDs_.
1105 size_type numValidRemote = 0;
1106#ifdef HAVE_TPETRA_DEBUG
1107 ArrayView<GO> remoteGIDsPtr = remoteGIDsView;
1108#else
1109 GO* const remoteGIDsPtr = remoteGIDsView.getRawPtr();
1110#endif // HAVE_TPETRA_DEBUG
1111
1112 // Don't mark the DualView modified, since we'll reallocate it.
1113 auto remoteLIDs = this->TransferData_->remoteLIDs_.view_host();
1114
1115 for (size_type r = 0; r < totalNumRemote; ++r) {
1116 // Pack in all the valid remote PIDs and GIDs.
1117 if (remoteProcIDs[r] != -1) {
1118 remoteProcIDs[numValidRemote] = remoteProcIDs[r];
1119 remoteGIDsPtr[numValidRemote] = remoteGIDsPtr[r];
1120 remoteLIDs[numValidRemote] = remoteLIDs[r];
1121 ++numValidRemote;
1122 }
1123 }
1124 TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC(numValidRemote != totalNumRemote - numInvalidRemote,
1125 std::logic_error,
1126 "After removing invalid remote GIDs and packing "
1127 "the valid remote GIDs, numValidRemote = "
1128 << numValidRemote
1129 << " != totalNumRemote - numInvalidRemote = "
1130 << totalNumRemote - numInvalidRemote
1131 << ". Please report this bug to the Tpetra developers.");
1132
1133 remoteProcIDs.resize(numValidRemote);
1134 remoteGIDs.resize(numValidRemote);
1135
1136 Kokkos::resize(remoteLIDs, numValidRemote);
1137 this->TransferData_->remoteLIDs_ = decltype(this->TransferData_->remoteLIDs_)();
1138 makeDualViewFromOwningHostView(this->TransferData_->remoteLIDs_, remoteLIDs);
1139 }
1140 // Revalidate the view after clear or resize.
1141 remoteGIDsView = remoteGIDs();
1142 }
1143
1144 // Sort remoteProcIDs in ascending order, and apply the resulting
1145 // permutation to remoteGIDs and remoteLIDs_. This ensures that
1146 // remoteProcIDs[i], remoteGIDs[i], and remoteLIDs_[i] all refer
1147 // to the same thing.
1148 {
1149 this->TransferData_->remoteLIDs_.modify_host();
1150 auto remoteLIDs = this->TransferData_->remoteLIDs_.view_host();
1151 sort3(remoteProcIDs.begin(),
1152 remoteProcIDs.end(),
1153 remoteGIDsView.getRawPtr(),
1154 remoteLIDs.data());
1155 this->TransferData_->remoteLIDs_.sync_device();
1156 }
1157
1158 // Call the Distributor's createFromRecvs() method to turn the
1159 // remote GIDs and their owning processes into a send-and-receive
1160 // communication plan. remoteGIDs and remoteProcIDs_ are input;
1161 // exportGIDs and exportProcIDs_ are output arrays which are
1162 // allocated by createFromRecvs().
1163 Array<GO> exportGIDs;
1164
1165 auto MM = Teuchos::rcp(new Tpetra::Details::ProfilingRegion("Tpetra:iport_ctor:setupExport:3"));
1166
1167 if (this->verbose()) {
1168 std::ostringstream os;
1169 os << *prefix << "Call createFromRecvs" << endl;
1170 this->verboseOutputStream() << endl;
1171 }
1172 this->TransferData_->distributor_.createFromRecvs(remoteGIDsView().getConst(),
1173 remoteProcIDs, exportGIDs,
1174 this->TransferData_->exportPIDs_);
1175
1176 // Find the LIDs corresponding to the (outgoing) GIDs in
1177 // exportGIDs. For sparse matrix-vector multiply, this tells the
1178 // calling process how to index into the source vector to get the
1179 // elements which it needs to send.
1180 MM = Teuchos::null;
1181 MM = Teuchos::rcp(new Tpetra::Details::ProfilingRegion("Tpetra:iport_ctor:setupExport:4"));
1182
1183 // NOTE (mfh 03 Mar 2014) This is now a candidate for a
1184 // thread-parallel kernel, but only if using the new thread-safe
1185 // Map implementation.
1186 const size_type numExportIDs = exportGIDs.size();
1187 if (numExportIDs > 0) {
1188 typename decltype(this->TransferData_->exportLIDs_)::t_host
1189 exportLIDs(view_alloc_no_init("exportLIDs"), numExportIDs);
1190 ArrayView<const GO> expGIDs = exportGIDs();
1191
1192 for (size_type k = 0; k < numExportIDs; ++k) {
1193 exportLIDs[k] = source.getLocalElement(expGIDs[k]);
1194 }
1195 makeDualViewFromOwningHostView(this->TransferData_->exportLIDs_, exportLIDs);
1196 }
1197
1198 if (this->verbose()) {
1199 std::ostringstream os;
1200 os << *prefix << "Done!" << endl;
1201 this->verboseOutputStream() << os.str();
1202 }
1203}
1204
1205template <class LocalOrdinal, class GlobalOrdinal, class Node>
1207 findUnionTargetGIDs(Teuchos::Array<GlobalOrdinal>& unionTgtGIDs,
1208 Teuchos::Array<std::pair<int, GlobalOrdinal>>& remotePGIDs,
1209 typename Teuchos::Array<GlobalOrdinal>::size_type& numSameGIDs,
1210 typename Teuchos::Array<GlobalOrdinal>::size_type& numPermuteGIDs,
1211 typename Teuchos::Array<GlobalOrdinal>::size_type& numRemoteGIDs,
1212 const Teuchos::ArrayView<const GlobalOrdinal>& sameGIDs1,
1213 const Teuchos::ArrayView<const GlobalOrdinal>& sameGIDs2,
1214 Teuchos::Array<GlobalOrdinal>& permuteGIDs1,
1215 Teuchos::Array<GlobalOrdinal>& permuteGIDs2,
1216 Teuchos::Array<GlobalOrdinal>& remoteGIDs1,
1217 Teuchos::Array<GlobalOrdinal>& remoteGIDs2,
1218 Teuchos::Array<int>& remotePIDs1,
1219 Teuchos::Array<int>& remotePIDs2) const {
1220 typedef GlobalOrdinal GO;
1221 typedef typename Teuchos::Array<GO>::size_type size_type;
1222
1223 const size_type numSameGIDs1 = sameGIDs1.size();
1224 const size_type numSameGIDs2 = sameGIDs2.size();
1225
1226 // Sort the permute GIDs
1227 std::sort(permuteGIDs1.begin(), permuteGIDs1.end());
1228 std::sort(permuteGIDs2.begin(), permuteGIDs2.end());
1229
1230 // Get the union of the two target maps
1231 // Reserve the maximum possible size to guard against reallocations from
1232 // push_back operations.
1234 permuteGIDs1.size() + permuteGIDs2.size() +
1235 remoteGIDs1.size() + remoteGIDs2.size());
1236
1237 // Copy the same GIDs to unionTgtGIDs. Cases for numSameGIDs1 !=
1238 // numSameGIDs2 must be treated separately.
1239 typename Teuchos::Array<GO>::iterator permuteGIDs1_end;
1240 typename Teuchos::Array<GO>::iterator permuteGIDs2_end;
1241 if (numSameGIDs2 > numSameGIDs1) {
1244
1245 // Copy the same GIDs from tgtGIDs to the union
1246 std::copy(sameGIDs2.begin(), sameGIDs2.end(), std::back_inserter(unionTgtGIDs));
1247
1248 // Remove GIDs from permuteGIDs1 that have already been copied in to unionTgtGIDs
1249 // set_difference allows the last (output) argument to alias the first.
1250 permuteGIDs1_end = std::set_difference(permuteGIDs1.begin(), permuteGIDs1.end(),
1251 unionTgtGIDs.begin() + numSameGIDs1, unionTgtGIDs.end(),
1252 permuteGIDs1.begin());
1253
1254 } else {
1257
1258 // Copy the same GIDs from tgtGIDs to the union
1259 std::copy(sameGIDs1.begin(), sameGIDs1.end(), std::back_inserter(unionTgtGIDs));
1260
1261 // Remove GIDs from permuteGIDs2 that have already been copied in to unionTgtGIDs
1262 // set_difference allows the last (output) argument to alias the first.
1263 permuteGIDs2_end = std::set_difference(permuteGIDs2.begin(), permuteGIDs2.end(),
1264 unionTgtGIDs.begin() + numSameGIDs2, unionTgtGIDs.end(),
1265 permuteGIDs2.begin());
1266 }
1267
1268 // Get the union of the permute GIDs and push it back on unionTgtGIDs
1269 std::set_union(permuteGIDs1.begin(), permuteGIDs1_end,
1271 std::back_inserter(unionTgtGIDs));
1272
1273 // Sort the PID,GID pairs and find the unique set
1274 Teuchos::Array<std::pair<int, GO>> remotePGIDs1(remoteGIDs1.size());
1275 for (size_type k = 0; k < remoteGIDs1.size(); k++)
1276 remotePGIDs1[k] = std::make_pair(remotePIDs1[k], remoteGIDs1[k]);
1277 std::sort(remotePGIDs1.begin(), remotePGIDs1.end());
1278
1279 Teuchos::Array<std::pair<int, GO>> remotePGIDs2(remoteGIDs2.size());
1280 for (size_type k = 0; k < remoteGIDs2.size(); k++)
1281 remotePGIDs2[k] = std::make_pair(remotePIDs2[k], remoteGIDs2[k]);
1282 std::sort(remotePGIDs2.begin(), remotePGIDs2.end());
1283
1284 remotePGIDs.reserve(remotePGIDs1.size() + remotePGIDs2.size());
1285 std::merge(remotePGIDs1.begin(), remotePGIDs1.end(),
1286 remotePGIDs2.begin(), remotePGIDs2.end(),
1287 std::back_inserter(remotePGIDs));
1288 auto it = std::unique(remotePGIDs.begin(), remotePGIDs.end());
1289 remotePGIDs.resize(std::distance(remotePGIDs.begin(), it));
1290
1291 // Finally, insert remote GIDs
1292 const size_type oldSize = unionTgtGIDs.size();
1293 unionTgtGIDs.resize(oldSize + remotePGIDs.size());
1294 for (size_type start = oldSize, k = 0; k < remotePGIDs.size(); k++)
1295 unionTgtGIDs[start + k] = remotePGIDs[k].second;
1296
1297 // Compute output only quantities
1298 numRemoteGIDs = remotePGIDs.size();
1300
1301 return;
1302}
1303
1304template <class LocalOrdinal, class GlobalOrdinal, class Node>
1305Teuchos::RCP<const Import<LocalOrdinal, GlobalOrdinal, Node>>
1308 using Teuchos::Array;
1309 using Teuchos::ArrayView;
1310 using Teuchos::as;
1311 using Teuchos::Comm;
1312 using Teuchos::outArg;
1313 using Teuchos::RCP;
1314 using Teuchos::rcp;
1315 using Teuchos::REDUCE_MIN;
1316 using Teuchos::reduceAll;
1317 using ::Tpetra::Details::Behavior;
1318 using GST = Tpetra::global_size_t;
1319 using LO = LocalOrdinal;
1320 using GO = GlobalOrdinal;
1321 using import_type = Import<LO, GO, Node>;
1322 using size_type = typename Array<GO>::size_type;
1323
1324 auto MM = Teuchos::rcp(new Tpetra::Details::ProfilingRegion("Tpetra::Import::setUnion"));
1325
1326 RCP<const map_type> srcMap = this->getSourceMap();
1327 RCP<const map_type> tgtMap1 = this->getTargetMap();
1328 RCP<const map_type> tgtMap2 = rhs.getTargetMap();
1329 RCP<const Comm<int>> comm = srcMap->getComm();
1330
1331 const bool debug = Behavior::debug("Import::setUnion") ||
1332 Behavior::debug("Tpetra::Import::setUnion");
1333
1334 if (debug) {
1335 TEUCHOS_TEST_FOR_EXCEPTION(!srcMap->isSameAs(*(rhs.getSourceMap())), std::invalid_argument,
1336 "Tpetra::Import::setUnion: The source Map of the input Import must be the "
1337 "same as (in the sense of Map::isSameAs) the source Map of this Import.");
1338 const Comm<int>& comm1 = *(tgtMap1->getComm());
1339 const Comm<int>& comm2 = *(tgtMap2->getComm());
1341 std::invalid_argument,
1342 "Tpetra::Import::setUnion: "
1343 "The target Maps must have congruent communicators.");
1344 }
1345
1346 // It's probably worth the one all-reduce to check whether the two
1347 // Maps are the same. If so, we can just return a copy of *this.
1348 // isSameAs() bypasses the all-reduce if the pointers are equal.
1349 if (tgtMap1->isSameAs(*tgtMap2)) {
1350 return rcp(new import_type(*this));
1351 }
1352
1353 // Alas, the two target Maps are not the same. That means we have
1354 // to compute their union, and the union Import object.
1355
1356 // Get the same GIDs (same GIDs are a subview of the first numSame target
1357 // GIDs)
1358 const size_type numSameGIDs1 = this->getNumSameIDs();
1359 ArrayView<const GO> sameGIDs1 = (tgtMap1->getLocalElementList())(0, numSameGIDs1);
1360
1361 const size_type numSameGIDs2 = rhs.getNumSameIDs();
1362 ArrayView<const GO> sameGIDs2 = (tgtMap2->getLocalElementList())(0, numSameGIDs2);
1363
1364 // Get permute GIDs
1365 ArrayView<const LO> permuteToLIDs1 = this->getPermuteToLIDs();
1367 for (size_type k = 0; k < permuteGIDs1.size(); k++)
1368 permuteGIDs1[k] = tgtMap1->getGlobalElement(permuteToLIDs1[k]);
1369
1370 ArrayView<const LO> permuteToLIDs2 = rhs.getPermuteToLIDs();
1372 for (size_type k = 0; k < permuteGIDs2.size(); k++)
1373 permuteGIDs2[k] = tgtMap2->getGlobalElement(permuteToLIDs2[k]);
1374
1375 // Get remote GIDs
1376 ArrayView<const LO> remoteLIDs1 = this->getRemoteLIDs();
1378 for (size_type k = 0; k < remoteLIDs1.size(); k++)
1379 remoteGIDs1[k] = this->getTargetMap()->getGlobalElement(remoteLIDs1[k]);
1380
1381 ArrayView<const LO> remoteLIDs2 = rhs.getRemoteLIDs();
1383 for (size_type k = 0; k < remoteLIDs2.size(); k++)
1384 remoteGIDs2[k] = rhs.getTargetMap()->getGlobalElement(remoteLIDs2[k]);
1385
1386 // Get remote PIDs
1388 Tpetra::Import_Util::getRemotePIDs(*this, remotePIDs1);
1389
1391 Tpetra::Import_Util::getRemotePIDs(rhs, remotePIDs2);
1392
1393 // Get the union of the target GIDs
1397
1398 findUnionTargetGIDs(unionTgtGIDs, remotePGIDs,
1402
1403 // Extract GIDs and compute LIDS, PIDs for the remotes in the union
1408 for (size_type k = 0; k < numRemoteIDsUnion; ++k) {
1410 remotePIDsUnion[k] = remotePGIDs[k].first;
1411 remoteGIDsUnion[k] = remotePGIDs[k].second;
1412 }
1413
1414 // Compute the permute-to LIDs (in the union target Map).
1415 // Convert the permute GIDs to permute-from LIDs in the source Map.
1418
1419 for (size_type k = 0; k < numPermuteIDsUnion; ++k) {
1420 size_type idx = numSameIDsUnion + k;
1421 permuteToLIDsUnion[k] = static_cast<LO>(idx);
1422 permuteFromLIDsUnion[k] = srcMap->getLocalElement(unionTgtGIDs[idx]);
1423 }
1424
1425 MM = Teuchos::null;
1426 auto MM2 = Teuchos::rcp(new Tpetra::Details::ProfilingRegion("Tpetra::Import::setUnion : Construct Target Map"));
1427
1428 // Create the union target Map.
1429 const GST INVALID = Teuchos::OrdinalTraits<GST>::invalid();
1430 const GO indexBaseUnion = std::min(tgtMap1->getIndexBase(), tgtMap2->getIndexBase());
1433
1434 MM2 = Teuchos::null;
1435 auto MM3 = Teuchos::rcp(new Tpetra::Details::ProfilingRegion("Tpetra::Import::setUnion : Export GIDs"));
1436
1437 // Thus far, we have computed the following in the union Import:
1438 // - numSameIDs
1439 // - numPermuteIDs and permuteFromLIDs
1440 // - numRemoteIDs, remoteGIDs, remoteLIDs, and remotePIDs
1441 //
1442 // Now it's time to compute the export IDs and initialize the
1443 // Distributor.
1444
1448 Distributor distributor(comm, this->TransferData_->out_);
1449
1450#ifdef TPETRA_IMPORT_SETUNION_USE_CREATE_FROM_SENDS
1451 // Compute the export IDs without communication, by merging the
1452 // lists of (export LID, export PID) pairs from the two input
1453 // Import objects. The export LIDs in both input Import objects
1454 // are LIDs in the source Map. Then, use the export PIDs to
1455 // initialize the Distributor via createFromSends.
1456
1457 // const size_type numExportIDs1 = this->getNumExportIDs ();
1458 ArrayView<const LO> exportLIDs1 = this->getExportLIDs();
1459 ArrayView<const LO> exportPIDs1 = this->getExportPIDs();
1460
1461 // const size_type numExportIDs2 = rhs.getNumExportIDs ();
1462 ArrayView<const LO> exportLIDs2 = rhs.getExportLIDs();
1463 ArrayView<const LO> exportPIDs2 = rhs.getExportPIDs();
1464
1465 // We have to keep the export LIDs in PID-sorted order, then merge
1466 // them. So, first key-value merge (LID,PID) pairs, treating PIDs
1467 // as values, merging values by replacement. Then, sort the
1468 // (LID,PID) pairs again by PID.
1469
1470 // Sort (LID,PID) pairs by LID for the later merge, and make
1471 // each sequence unique by LID.
1474 sort2(exportLIDs1Copy.begin(), exportLIDs1Copy.end(),
1475 exportPIDs1Copy.begin());
1482
1485 sort2(exportLIDs2Copy.begin(), exportLIDs2Copy.end(),
1486 exportPIDs2Copy.begin());
1493
1494 // Merge export (LID,PID) pairs. In this merge operation, the
1495 // LIDs are the "keys" and the PIDs their "values." We combine
1496 // the "values" (PIDs) in the pairs by replacement, rather than
1497 // by adding them together.
1499 exportPIDs1Copy.begin(), exportPIDs1Copy.end(),
1500 exportLIDs2Copy.begin(), exportLIDs2Copy.end(),
1501 exportPIDs2Copy.begin(), exportPIDs2Copy.end(),
1502 std::back_inserter(exportLIDsUnion),
1503 std::back_inserter(exportPIDsUnion),
1505
1506 // Resort the merged (LID,PID) pairs by PID.
1507 sort2(exportPIDsUnion.begin(), exportPIDsUnion.end(),
1508 exportLIDsUnion.begin());
1509
1510 // Initialize the Distributor. Using createFromSends instead of
1511 // createFromRecvs avoids the initialization and use of a
1512 // temporary Distributor object.
1513 (void)distributor.createFromSends(exportPIDsUnion().getConst());
1514#else // NOT TPETRA_IMPORT_SETUNION_USE_CREATE_FROM_SENDS
1515
1516 // Call the Distributor's createFromRecvs() method to turn the
1517 // remote GIDs and their owning processes into a send-and-receive
1518 // communication plan. remoteGIDsUnion and remotePIDsUnion are
1519 // input; exportGIDsUnion and exportPIDsUnion are output arrays
1520 // which are allocated by createFromRecvs().
1521 distributor.createFromRecvs(remoteGIDsUnion().getConst(),
1522 remotePIDsUnion().getConst(),
1524
1525 // Find the (source Map) LIDs corresponding to the export GIDs.
1526 const size_type numExportIDsUnion = exportGIDsUnion.size();
1528 for (size_type k = 0; k < numExportIDsUnion; ++k) {
1529 exportLIDsUnion[k] = srcMap->getLocalElement(exportGIDsUnion[k]);
1530 }
1531#endif // TPETRA_IMPORT_SETUNION_USE_CREATE_FROM_SENDS
1532
1533 // Create and return the union Import. This uses the "expert" constructor
1534 MM3 = Teuchos::null;
1535 auto MM4 = Teuchos::rcp(new Tpetra::Details::ProfilingRegion("Tpetra::Import::setUnion : Construct Import"));
1537 rcp(new import_type(srcMap, unionTgtMap,
1542 this->TransferData_->out_));
1543 return unionImport;
1544}
1545
1546template <class LocalOrdinal, class GlobalOrdinal, class Node>
1547Teuchos::RCP<const Import<LocalOrdinal, GlobalOrdinal, Node>>
1549 setUnion() const {
1550 using Teuchos::Array;
1551 using Teuchos::ArrayView;
1552 using Teuchos::as;
1553 using Teuchos::Comm;
1554 using Teuchos::outArg;
1555 using Teuchos::RCP;
1556 using Teuchos::rcp;
1557 using Teuchos::REDUCE_MIN;
1558 using Teuchos::reduceAll;
1559 typedef LocalOrdinal LO;
1560 typedef GlobalOrdinal GO;
1561 Teuchos::RCP<const Import<LocalOrdinal, GlobalOrdinal, Node>> unionImport;
1562 RCP<const map_type> srcMap = this->getSourceMap();
1563 RCP<const map_type> tgtMap = this->getTargetMap();
1564 RCP<const Comm<int>> comm = srcMap->getComm();
1565
1566 ArrayView<const GO> srcGIDs = srcMap->getLocalElementList();
1567 ArrayView<const GO> tgtGIDs = tgtMap->getLocalElementList();
1568
1569 // All elements in srcMap will be in the "new" target map, so...
1570 size_t numSameIDsNew = srcMap->getLocalNumElements();
1571 size_t numRemoteIDsNew = this->getNumRemoteIDs();
1572 Array<LO> permuteToLIDsNew, permuteFromLIDsNew; // empty on purpose
1573
1574 // Grab some old data
1575 ArrayView<const LO> remoteLIDsOld = this->getRemoteLIDs();
1576 ArrayView<const LO> exportLIDsOld = this->getExportLIDs();
1577
1578 // Build up the new map (same part)
1580 for (size_t i = 0; i < numSameIDsNew; i++)
1581 GIDs[i] = srcGIDs[i];
1582
1583 // Build up the new map (remote part) and remotes list
1585 for (size_t i = 0; i < numRemoteIDsNew; i++) {
1588 }
1589
1590 // Build the new target map
1591 GO GO_INVALID = Teuchos::OrdinalTraits<GO>::invalid();
1593 rcp(new map_type(GO_INVALID, GIDs, tgtMap->getIndexBase(),
1594 tgtMap->getComm()));
1595
1596 // Exports are trivial (since the sourcemap doesn't change)
1597 Array<int> exportPIDsnew(this->getExportPIDs());
1598 Array<LO> exportLIDsnew(this->getExportLIDs());
1599
1600 // Copy the Distributor (due to how the Import constructor works)
1601 Distributor D(this->getDistributor());
1602
1603 // Build the importer using the "expert" constructor
1611 exportPIDsnew, D));
1612
1613 return unionImport;
1614}
1615
1616template <class LocalOrdinal, class GlobalOrdinal, class Node>
1617Teuchos::RCP<const Import<LocalOrdinal, GlobalOrdinal, Node>>
1619 createRemoteOnlyImport(const Teuchos::RCP<const map_type>& remoteTarget) const {
1620 using std::endl;
1621 using Teuchos::outArg;
1622 using Teuchos::rcp;
1623 using Teuchos::REDUCE_MIN;
1624 using Teuchos::reduceAll;
1625 using ::Tpetra::Details::Behavior;
1626 using ::Tpetra::Details::gathervPrint;
1627 using LO = LocalOrdinal;
1628 using GO = GlobalOrdinal;
1630
1631 const char funcPrefix[] = "Tpetra::createRemoteOnlyImport: ";
1632 int lclSuccess = 1;
1633 int gblSuccess = 1;
1634 const bool debug = Behavior::debug();
1635
1636 const size_t NumRemotes = this->getNumRemoteIDs();
1637 std::unique_ptr<std::string> procPrefix;
1638 Teuchos::RCP<const Teuchos::Comm<int>> comm;
1639 if (debug) {
1640 comm = remoteTarget.is_null() ? Teuchos::null : remoteTarget->getComm();
1641 std::ostringstream os;
1642 os << "Proc ";
1643 if (comm.is_null()) {
1644 os << "?";
1645 } else {
1646 os << comm->getRank();
1647 }
1648 os << ": ";
1649 procPrefix = std::unique_ptr<std::string>(new std::string(os.str()));
1650 }
1651
1652 if (debug) {
1653 std::ostringstream lclErr;
1654 if (remoteTarget.is_null()) {
1655 lclSuccess = -1;
1656 } else if (NumRemotes != remoteTarget->getLocalNumElements()) {
1657 lclSuccess = 0;
1658 lclErr << *procPrefix << "getNumRemoteIDs() = " << NumRemotes
1659 << " != remoteTarget->getLocalNumElements() = "
1660 << remoteTarget->getLocalNumElements() << "." << endl;
1661 }
1662
1663 if (comm.is_null()) {
1665 } else {
1667 }
1668 TEUCHOS_TEST_FOR_EXCEPTION(gblSuccess == -1, std::invalid_argument, funcPrefix << "Input target Map is null on at least one process.");
1669
1670 if (gblSuccess != 1) {
1671 if (comm.is_null()) {
1672 TEUCHOS_TEST_FOR_EXCEPTION(true, std::runtime_error, lclErr.str());
1673 } else {
1674 std::ostringstream gblErr;
1675 gblErr << funcPrefix << endl;
1676 gathervPrint(gblErr, lclErr.str(), *comm);
1677 TEUCHOS_TEST_FOR_EXCEPTION(true, std::runtime_error, gblErr.str());
1678 }
1679 }
1680 }
1681
1682 // Compute the new Remote LIDs
1683 Teuchos::ArrayView<const LO> oldRemoteLIDs = this->getRemoteLIDs();
1684 Teuchos::Array<LO> newRemoteLIDs(NumRemotes);
1685 const map_type& tgtMap = *(this->getTargetMap());
1686 size_t badCount = 0;
1687
1688 std::unique_ptr<std::vector<size_t>> badIndices;
1689 if (debug) {
1690 badIndices = std::unique_ptr<std::vector<size_t>>(new std::vector<size_t>);
1691 }
1692
1693 for (size_t i = 0; i < NumRemotes; ++i) {
1694 const LO oldLclInd = oldRemoteLIDs[i];
1695 if (oldLclInd == Teuchos::OrdinalTraits<LO>::invalid()) {
1696 ++badCount;
1697 if (debug) {
1698 badIndices->push_back(i);
1699 }
1700 continue;
1701 }
1702 const GO gblInd = tgtMap.getGlobalElement(oldLclInd);
1703 if (gblInd == Teuchos::OrdinalTraits<GO>::invalid()) {
1704 ++badCount;
1705 if (debug) {
1706 badIndices->push_back(i);
1707 }
1708 continue;
1709 }
1710 const LO newLclInd = remoteTarget->getLocalElement(gblInd);
1711 if (newLclInd == Teuchos::OrdinalTraits<LO>::invalid()) {
1712 ++badCount;
1713 if (debug) {
1714 badIndices->push_back(i);
1715 }
1716 continue;
1717 }
1719 // Now we make sure these guys are in sorted order (AztecOO-ML ordering)
1720 if (i > 0 && newRemoteLIDs[i] < newRemoteLIDs[i - 1]) {
1721 ++badCount;
1722 if (debug) {
1723 badIndices->push_back(i);
1724 }
1725 }
1726 }
1727
1728 if (badCount != 0) {
1729 lclSuccess = 0;
1730 }
1731
1732 if (debug) {
1733 if (comm.is_null()) {
1735 } else {
1737 }
1738 std::ostringstream lclErr;
1739 if (lclSuccess != 1) {
1740 lclErr << *procPrefix << "Count of bad indices: " << badCount
1741 << ", bad indices: [";
1742 // TODO (mfh 04 Sep 2019) Limit the maximum number of bad
1743 // indices to print.
1744 for (size_t k = 0; k < badCount; ++k) {
1745 const size_t badIndex = (*badIndices)[k];
1746 lclErr << "(" << badIndex << ","
1747 << oldRemoteLIDs[badIndex] << ")";
1748 if (k + size_t(1) < badCount) {
1749 lclErr << ", ";
1750 }
1751 }
1752 lclErr << "]" << endl;
1753 }
1754
1755 if (gblSuccess != 1) {
1756 std::ostringstream gblErr;
1757 gblErr << funcPrefix << "this->getRemoteLIDs() has \"bad\" "
1758 "indices on one or more processes. \"Bad\" means that the "
1759 "indices are invalid, they don't exist in the target Map, "
1760 "they don't exist in remoteTarget, or they are not in "
1761 "sorted order. In what follows, I will show the \"bad\" "
1762 "indices as (k, LID) pairs, where k is the zero-based "
1763 "index of the LID in this->getRemoteLIDs()."
1764 << endl;
1765 if (comm.is_null()) {
1766 gblErr << lclErr.str();
1767 } else {
1768 gathervPrint(gblErr, lclErr.str(), *comm);
1769 }
1770 TEUCHOS_TEST_FOR_EXCEPTION(true, std::runtime_error, gblErr.str());
1771 }
1772 } else { // not debug
1773 TEUCHOS_TEST_FOR_EXCEPTION(lclSuccess == 0, std::runtime_error, funcPrefix << "this->getRemoteLIDs() has " << badCount << "ind" << (badCount == 1 ? "ex" : "ices") << " \"bad\" indices on this process." << endl);
1774 }
1775
1776 // Copy ExportPIDs and such
1777 // NOTE: Be careful: The "Expert" Import constructor we use does a "swap"
1778 // for most of the LID/PID lists and the Distributor, meaning it
1779 // ruins the existing object if we pass things in directly. Hence
1780 // we copy them first.
1781 Teuchos::Array<int> newExportPIDs(this->getExportPIDs());
1782 Teuchos::Array<LO> newExportLIDs(this->getExportLIDs());
1783 Teuchos::Array<LO> dummy;
1784 Distributor newDistor(this->getDistributor());
1785
1786 return rcp(new import_type(this->getSourceMap(), remoteTarget,
1787 static_cast<size_t>(0), dummy, dummy,
1790}
1791
1792} // namespace Tpetra
1793
1794#define TPETRA_IMPORT_CLASS_INSTANT(LO, GO, NODE) \
1795 template class Import<LO, GO, NODE>;
1796
1797// Explicit instantiation macro.
1798// Only invoke this when in the Tpetra namespace.
1799// Most users do not need to use this.
1800//
1801// LO: The local ordinal type.
1802// GO: The global ordinal type.
1803// NODE: The Kokkos Node type.
1804#define TPETRA_IMPORT_INSTANT(LO, GO, NODE) \
1805 TPETRA_IMPORT_CLASS_INSTANT(LO, GO, NODE)
1806
1807#endif // TPETRA_IMPORT_DEF_HPP
Declaration of Tpetra::Details::Behavior, a class that describes Tpetra's behavior.
Declaration of Tpetra::Details::Profiling, a scope guard for Kokkos Profiling.
Declaration of a function that prints strings from each process.
Internal functions and macros designed for use with Tpetra::Import and Tpetra::Export objects.
Stand-alone utility functions and macros.
#define TPETRA_ABUSE_WARNING(throw_exception_test, Exception, msg)
Handle an abuse warning, according to HAVE_TPETRA_THROW_ABUSE_WARNINGS and HAVE_TPETRA_PRINT_ABUSE_WA...
Struct that holds views of the contents of a CrsMatrix.
size_t getNumRemoteIDs() const
Number of entries not on the calling process.
bool verbose() const
Whether to print verbose debugging output.
Teuchos::RCP< ImportExportData< LocalOrdinal, GlobalOrdinal, Node > > TransferData_
All the data needed for executing the Export communication plan.
Teuchos::FancyOStream & verboseOutputStream() const
Valid (nonnull) output stream for verbose output.
Sets up and executes a communication plan for a Tpetra DistObject.
void createFromRecvs(const Teuchos::ArrayView< const Ordinal > &remoteIDs, const Teuchos::ArrayView< const int > &remoteProcIDs, Teuchos::Array< Ordinal > &exportIDs, Teuchos::Array< int > &exportProcIDs)
Set up Distributor using list of process ranks from which to receive.
void createFromSendsAndRecvs(const Teuchos::ArrayView< const int > &exportProcIDs, const Teuchos::ArrayView< const int > &remoteProcIDs)
Set up Distributor using list of process ranks to which to send, and list of process ranks from which...
Communication plan for data redistribution from a uniquely-owned to a (possibly) multiply-owned distr...
Teuchos::RCP< const Import< LocalOrdinal, GlobalOrdinal, Node > > setUnion() const
Return the union of this Import this->getSourceMap()
virtual void describe(Teuchos::FancyOStream &out, const Teuchos::EVerbosityLevel verbLevel=Teuchos::Describable::verbLevel_default) const
Describe this object in a human-readable way to the given output stream.
Teuchos::RCP< const Import< LocalOrdinal, GlobalOrdinal, Node > > createRemoteOnlyImport(const Teuchos::RCP< const map_type > &remoteTarget) const
Returns an importer that contains only the remote entries of this.
Import(const Teuchos::RCP< const map_type > &source, const Teuchos::RCP< const map_type > &target)
Construct an Import from the source and target Maps.
void findUnionTargetGIDs(Teuchos::Array< GlobalOrdinal > &unionTgtGIDs, Teuchos::Array< std::pair< int, GlobalOrdinal > > &remotePGIDs, typename Teuchos::Array< GlobalOrdinal >::size_type &numSameGIDs, typename Teuchos::Array< GlobalOrdinal >::size_type &numPermuteGIDs, typename Teuchos::Array< GlobalOrdinal >::size_type &numRemoteGIDs, const Teuchos::ArrayView< const GlobalOrdinal > &sameGIDs1, const Teuchos::ArrayView< const GlobalOrdinal > &sameGIDs2, Teuchos::Array< GlobalOrdinal > &permuteGIDs1, Teuchos::Array< GlobalOrdinal > &permuteGIDs2, Teuchos::Array< GlobalOrdinal > &remoteGIDs1, Teuchos::Array< GlobalOrdinal > &remoteGIDs2, Teuchos::Array< int > &remotePIDs1, Teuchos::Array< int > &remotePIDs2) const
Find the union of the target IDs from two Import objects.
virtual void print(std::ostream &os) const
Print the Import's data to the given output stream.
A parallel distribution of indices over processes.
auto view_alloc_no_init(const std::string &label) -> decltype(Kokkos::view_alloc(label, Kokkos::WithoutInitializing))
Use in place of the string label as the first argument of Kokkos::View's constructor,...
void makeDualViewFromOwningHostView(Kokkos::DualView< ElementType *, DeviceType > &dv, const typename Kokkos::DualView< ElementType *, DeviceType >::t_host &hostView)
Initialize dv such that its host View is hostView.
bool congruent(const Teuchos::Comm< int > &comm1, const Teuchos::Comm< int > &comm2)
Whether the two communicators are congruent.
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 sort2(const IT1 &first1, const IT1 &last1, const IT2 &first2, const bool stableSort=false)
Sort the first array, and apply the resulting permutation to the second array.
LookupStatus
Return status of Map remote index lookup (getRemoteIndexList()).
size_t global_size_t
Global size_t object.
void merge2(IT1 &indResultOut, IT2 &valResultOut, IT1 indBeg, IT1 indEnd, IT2 valBeg, IT2)
Merge values in place, additively, with the same index.
void keyValueMerge(KeyInputIterType keyBeg1, KeyInputIterType keyEnd1, ValueInputIterType valBeg1, ValueInputIterType valEnd1, KeyInputIterType keyBeg2, KeyInputIterType keyEnd2, ValueInputIterType valBeg2, ValueInputIterType valEnd2, KeyOutputIterType keyOut, ValueOutputIterType valOut, BinaryFunction f)
Merge two sorted (by keys) sequences of unique (key,value) pairs by combining pairs with equal keys.
void sort3(const IT1 &first1, const IT1 &last1, const IT2 &first2, const IT3 &first3, const bool stableSort=false)
Sort the first array, and apply the same permutation to the second and third arrays.