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 if (!useRemotePIDs && !this->getSourceMap()->haveGlobalConstants()) {
1018 // Directory construction below requires global constants
1019 Teuchos::rcp_const_cast<Map<LocalOrdinal, GlobalOrdinal, Node>>(this->getSourceMap())->computeGlobalConstants();
1020 }
1021 const map_type& source = *(this->getSourceMap());
1022
1023 TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC(!useRemotePIDs && (userRemotePIDs.size() > 0), std::invalid_argument,
1024 "remotePIDs are non-empty but their use has not been requested.");
1025 TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC(userRemotePIDs.size() > 0 && remoteGIDs.size() != userRemotePIDs.size(),
1026 std::invalid_argument,
1027 "remotePIDs must either be of size zero or match "
1028 "the size of remoteGIDs.");
1029
1030 // For each entry remoteGIDs[i], remoteProcIDs[i] will contain
1031 // the process ID of the process that owns that GID.
1032 ArrayView<GO> remoteGIDsView = remoteGIDs();
1033 ArrayView<int> remoteProcIDsView;
1034
1035 // lookup == IDNotPresent means that the source Map wasn't able to
1036 // figure out to which processes one or more of the GIDs in the
1037 // given list of remote GIDs belong.
1038 //
1039 // The previous abuse warning said "The target Map has GIDs not
1040 // found in the source Map." This statement could be confusing,
1041 // because it doesn't refer to ownership by the current process,
1042 // but rather to ownership by _any_ process participating in the
1043 // Map. (It could not possibly refer to ownership by the current
1044 // process, since remoteGIDs is exactly the list of GIDs owned by
1045 // the target Map but not owned by the source Map. It was
1046 // constructed that way by setupSamePermuteRemote().)
1047 //
1048 // What this statement means is that the source and target Maps
1049 // don't contain the same set of GIDs globally (over all
1050 // processes). That is, there is at least one GID owned by some
1051 // process in the target Map, which is not owned by _any_ process
1052 // in the source Map.
1053 Array<int> newRemotePIDs;
1054 LookupStatus lookup = AllIDsPresent;
1055
1056 if (!useRemotePIDs) {
1057 newRemotePIDs.resize(remoteGIDsView.size());
1058 if (this->verbose()) {
1059 std::ostringstream os;
1060 os << *prefix << "Call sourceMap.getRemoteIndexList" << endl;
1061 this->verboseOutputStream() << os.str();
1062 }
1063 lookup = source.getRemoteIndexList(remoteGIDsView, newRemotePIDs());
1064 }
1065 Array<int>& remoteProcIDs = useRemotePIDs ? userRemotePIDs : newRemotePIDs;
1066
1067 if (lookup == IDNotPresent) {
1068 Tpetra::Details::ProfilingRegion pr("Tpetra:iport_ctor:setupExport:1");
1069 // There is at least one GID owned by the calling process in the
1070 // target Map, which is not owned by any process in the source
1071 // Map.
1072 this->TransferData_->isLocallyComplete_ = false;
1073
1074 // mfh 12 Sep 2016: I disagree that this is "abuse"; it may be
1075 // correct behavior, depending on the circumstances.
1076 TPETRA_ABUSE_WARNING(true, std::runtime_error,
1077 "::setupExport(): the source Map wasn't "
1078 "able to figure out which process owns one or more of the GIDs in the "
1079 "list of remote GIDs. This probably means that there is at least one "
1080 "GID owned by some process in the target Map which is not owned by any"
1081 " process in the source Map. (That is, the source and target Maps do "
1082 "not contain the same set of GIDs globally.)");
1083
1084 // Ignore remote GIDs that aren't owned by any process in the
1085 // source Map. getRemoteIndexList() gives each of these a
1086 // process ID of -1.
1087
1088 const size_type numInvalidRemote =
1089 std::count_if(remoteProcIDs.begin(), remoteProcIDs.end(),
1090 std::bind(std::equal_to<int>(), -1, std::placeholders::_1));
1091 TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC(numInvalidRemote == 0, std::logic_error,
1092 "Calling getRemoteIndexList "
1093 "on the source Map returned IDNotPresent, but none of the returned "
1094 "\"remote\" process ranks are -1. Please report this bug to the "
1095 "Tpetra developers.");
1096
1097 // If all of them are invalid, we can delete the whole array.
1098 const size_type totalNumRemote = this->getNumRemoteIDs();
1099 if (numInvalidRemote == totalNumRemote) {
1100 // all remotes are invalid; we have no remotes; we can delete the remotes
1101 remoteProcIDs.clear();
1102 remoteGIDs.clear(); // invalidates remoteGIDsView
1103 this->TransferData_->remoteLIDs_ =
1104 decltype(this->TransferData_->remoteLIDs_)();
1105 } else {
1106 // Some remotes are valid; we need to keep the valid ones.
1107 // Pack and resize remoteProcIDs, remoteGIDs, and remoteLIDs_.
1108 size_type numValidRemote = 0;
1109#ifdef HAVE_TPETRA_DEBUG
1110 ArrayView<GO> remoteGIDsPtr = remoteGIDsView;
1111#else
1112 GO* const remoteGIDsPtr = remoteGIDsView.getRawPtr();
1113#endif // HAVE_TPETRA_DEBUG
1114
1115 // Don't mark the DualView modified, since we'll reallocate it.
1116 auto remoteLIDs = this->TransferData_->remoteLIDs_.view_host();
1117
1118 for (size_type r = 0; r < totalNumRemote; ++r) {
1119 // Pack in all the valid remote PIDs and GIDs.
1120 if (remoteProcIDs[r] != -1) {
1121 remoteProcIDs[numValidRemote] = remoteProcIDs[r];
1122 remoteGIDsPtr[numValidRemote] = remoteGIDsPtr[r];
1123 remoteLIDs[numValidRemote] = remoteLIDs[r];
1124 ++numValidRemote;
1125 }
1126 }
1127 TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC(numValidRemote != totalNumRemote - numInvalidRemote,
1128 std::logic_error,
1129 "After removing invalid remote GIDs and packing "
1130 "the valid remote GIDs, numValidRemote = "
1131 << numValidRemote
1132 << " != totalNumRemote - numInvalidRemote = "
1133 << totalNumRemote - numInvalidRemote
1134 << ". Please report this bug to the Tpetra developers.");
1135
1136 remoteProcIDs.resize(numValidRemote);
1137 remoteGIDs.resize(numValidRemote);
1138
1139 Kokkos::resize(remoteLIDs, numValidRemote);
1140 this->TransferData_->remoteLIDs_ = decltype(this->TransferData_->remoteLIDs_)();
1141 makeDualViewFromOwningHostView(this->TransferData_->remoteLIDs_, remoteLIDs);
1142 }
1143 // Revalidate the view after clear or resize.
1144 remoteGIDsView = remoteGIDs();
1145 }
1146
1147 // Sort remoteProcIDs in ascending order, and apply the resulting
1148 // permutation to remoteGIDs and remoteLIDs_. This ensures that
1149 // remoteProcIDs[i], remoteGIDs[i], and remoteLIDs_[i] all refer
1150 // to the same thing.
1151 {
1152 Tpetra::Details::ProfilingRegion pr("Tpetra:iport_ctor:setupExport:2");
1153 this->TransferData_->remoteLIDs_.modify_host();
1154 auto remoteLIDs = this->TransferData_->remoteLIDs_.view_host();
1155 sort3(remoteProcIDs.begin(),
1156 remoteProcIDs.end(),
1157 remoteGIDsView.getRawPtr(),
1158 remoteLIDs.data());
1159 this->TransferData_->remoteLIDs_.sync_device();
1160 }
1161
1162 // Call the Distributor's createFromRecvs() method to turn the
1163 // remote GIDs and their owning processes into a send-and-receive
1164 // communication plan. remoteGIDs and remoteProcIDs_ are input;
1165 // exportGIDs and exportProcIDs_ are output arrays which are
1166 // allocated by createFromRecvs().
1167 Array<GO> exportGIDs;
1168 {
1169 Tpetra::Details::ProfilingRegion pr("Tpetra:iport_ctor:setupExport:3");
1170
1171 if (this->verbose()) {
1172 std::ostringstream os;
1173 os << *prefix << "Call createFromRecvs" << endl;
1174 this->verboseOutputStream() << endl;
1175 }
1176 this->TransferData_->distributor_.createFromRecvs(remoteGIDsView().getConst(),
1177 remoteProcIDs, exportGIDs,
1178 this->TransferData_->exportPIDs_);
1179 }
1180 // Find the LIDs corresponding to the (outgoing) GIDs in
1181 // exportGIDs. For sparse matrix-vector multiply, this tells the
1182 // calling process how to index into the source vector to get the
1183 // elements which it needs to send.
1184 Tpetra::Details::ProfilingRegion pr("Tpetra:iport_ctor:setupExport:4");
1185
1186 // NOTE (mfh 03 Mar 2014) This is now a candidate for a
1187 // thread-parallel kernel, but only if using the new thread-safe
1188 // Map implementation.
1189 const size_type numExportIDs = exportGIDs.size();
1190 if (numExportIDs > 0) {
1191 typename decltype(this->TransferData_->exportLIDs_)::t_host
1192 exportLIDs(view_alloc_no_init("exportLIDs"), numExportIDs);
1193 ArrayView<const GO> expGIDs = exportGIDs();
1194
1195 for (size_type k = 0; k < numExportIDs; ++k) {
1196 exportLIDs[k] = source.getLocalElement(expGIDs[k]);
1197 }
1198 makeDualViewFromOwningHostView(this->TransferData_->exportLIDs_, exportLIDs);
1199 }
1200
1201 if (this->verbose()) {
1202 std::ostringstream os;
1203 os << *prefix << "Done!" << endl;
1204 this->verboseOutputStream() << os.str();
1205 }
1206}
1207
1208template <class LocalOrdinal, class GlobalOrdinal, class Node>
1210 findUnionTargetGIDs(Teuchos::Array<GlobalOrdinal>& unionTgtGIDs,
1211 Teuchos::Array<std::pair<int, GlobalOrdinal>>& remotePGIDs,
1212 typename Teuchos::Array<GlobalOrdinal>::size_type& numSameGIDs,
1213 typename Teuchos::Array<GlobalOrdinal>::size_type& numPermuteGIDs,
1214 typename Teuchos::Array<GlobalOrdinal>::size_type& numRemoteGIDs,
1215 const Teuchos::ArrayView<const GlobalOrdinal>& sameGIDs1,
1216 const Teuchos::ArrayView<const GlobalOrdinal>& sameGIDs2,
1217 Teuchos::Array<GlobalOrdinal>& permuteGIDs1,
1218 Teuchos::Array<GlobalOrdinal>& permuteGIDs2,
1219 Teuchos::Array<GlobalOrdinal>& remoteGIDs1,
1220 Teuchos::Array<GlobalOrdinal>& remoteGIDs2,
1221 Teuchos::Array<int>& remotePIDs1,
1222 Teuchos::Array<int>& remotePIDs2) const {
1223 typedef GlobalOrdinal GO;
1224 typedef typename Teuchos::Array<GO>::size_type size_type;
1225
1226 const size_type numSameGIDs1 = sameGIDs1.size();
1227 const size_type numSameGIDs2 = sameGIDs2.size();
1228
1229 // Sort the permute GIDs
1230 std::sort(permuteGIDs1.begin(), permuteGIDs1.end());
1231 std::sort(permuteGIDs2.begin(), permuteGIDs2.end());
1232
1233 // Get the union of the two target maps
1234 // Reserve the maximum possible size to guard against reallocations from
1235 // push_back operations.
1237 permuteGIDs1.size() + permuteGIDs2.size() +
1238 remoteGIDs1.size() + remoteGIDs2.size());
1239
1240 // Copy the same GIDs to unionTgtGIDs. Cases for numSameGIDs1 !=
1241 // numSameGIDs2 must be treated separately.
1242 typename Teuchos::Array<GO>::iterator permuteGIDs1_end;
1243 typename Teuchos::Array<GO>::iterator permuteGIDs2_end;
1244 if (numSameGIDs2 > numSameGIDs1) {
1247
1248 // Copy the same GIDs from tgtGIDs to the union
1249 std::copy(sameGIDs2.begin(), sameGIDs2.end(), std::back_inserter(unionTgtGIDs));
1250
1251 // Remove GIDs from permuteGIDs1 that have already been copied in to unionTgtGIDs
1252 // set_difference allows the last (output) argument to alias the first.
1253 permuteGIDs1_end = std::set_difference(permuteGIDs1.begin(), permuteGIDs1.end(),
1254 unionTgtGIDs.begin() + numSameGIDs1, unionTgtGIDs.end(),
1255 permuteGIDs1.begin());
1256
1257 } else {
1260
1261 // Copy the same GIDs from tgtGIDs to the union
1262 std::copy(sameGIDs1.begin(), sameGIDs1.end(), std::back_inserter(unionTgtGIDs));
1263
1264 // Remove GIDs from permuteGIDs2 that have already been copied in to unionTgtGIDs
1265 // set_difference allows the last (output) argument to alias the first.
1266 permuteGIDs2_end = std::set_difference(permuteGIDs2.begin(), permuteGIDs2.end(),
1267 unionTgtGIDs.begin() + numSameGIDs2, unionTgtGIDs.end(),
1268 permuteGIDs2.begin());
1269 }
1270
1271 // Get the union of the permute GIDs and push it back on unionTgtGIDs
1272 std::set_union(permuteGIDs1.begin(), permuteGIDs1_end,
1274 std::back_inserter(unionTgtGIDs));
1275
1276 // Sort the PID,GID pairs and find the unique set
1277 Teuchos::Array<std::pair<int, GO>> remotePGIDs1(remoteGIDs1.size());
1278 for (size_type k = 0; k < remoteGIDs1.size(); k++)
1279 remotePGIDs1[k] = std::make_pair(remotePIDs1[k], remoteGIDs1[k]);
1280 std::sort(remotePGIDs1.begin(), remotePGIDs1.end());
1281
1282 Teuchos::Array<std::pair<int, GO>> remotePGIDs2(remoteGIDs2.size());
1283 for (size_type k = 0; k < remoteGIDs2.size(); k++)
1284 remotePGIDs2[k] = std::make_pair(remotePIDs2[k], remoteGIDs2[k]);
1285 std::sort(remotePGIDs2.begin(), remotePGIDs2.end());
1286
1287 remotePGIDs.reserve(remotePGIDs1.size() + remotePGIDs2.size());
1288 std::merge(remotePGIDs1.begin(), remotePGIDs1.end(),
1289 remotePGIDs2.begin(), remotePGIDs2.end(),
1290 std::back_inserter(remotePGIDs));
1291 auto it = std::unique(remotePGIDs.begin(), remotePGIDs.end());
1292 remotePGIDs.resize(std::distance(remotePGIDs.begin(), it));
1293
1294 // Finally, insert remote GIDs
1295 const size_type oldSize = unionTgtGIDs.size();
1296 unionTgtGIDs.resize(oldSize + remotePGIDs.size());
1297 for (size_type start = oldSize, k = 0; k < remotePGIDs.size(); k++)
1298 unionTgtGIDs[start + k] = remotePGIDs[k].second;
1299
1300 // Compute output only quantities
1301 numRemoteGIDs = remotePGIDs.size();
1303
1304 return;
1305}
1306
1307template <class LocalOrdinal, class GlobalOrdinal, class Node>
1308Teuchos::RCP<const Import<LocalOrdinal, GlobalOrdinal, Node>>
1311 const Teuchos::RCP<Teuchos::ParameterList>& params) const {
1312 using Teuchos::Array;
1313 using Teuchos::ArrayView;
1314 using Teuchos::as;
1315 using Teuchos::Comm;
1316 using Teuchos::outArg;
1317 using Teuchos::RCP;
1318 using Teuchos::rcp;
1319 using Teuchos::REDUCE_MIN;
1320 using Teuchos::reduceAll;
1321 using ::Tpetra::Details::Behavior;
1322 using GST = Tpetra::global_size_t;
1323 using LO = LocalOrdinal;
1324 using GO = GlobalOrdinal;
1325 using import_type = Import<LO, GO, Node>;
1326 using size_type = typename Array<GO>::size_type;
1327
1328 auto MM = Teuchos::rcp(new Tpetra::Details::ProfilingRegion("Tpetra::Import::setUnion"));
1329
1330 RCP<const map_type> srcMap = this->getSourceMap();
1331 RCP<const map_type> tgtMap1 = this->getTargetMap();
1332 RCP<const map_type> tgtMap2 = rhs.getTargetMap();
1333 RCP<const Comm<int>> comm = srcMap->getComm();
1334
1335 const bool debug = Behavior::debug("Import::setUnion") ||
1336 Behavior::debug("Tpetra::Import::setUnion");
1337
1338 if (debug) {
1339 TEUCHOS_TEST_FOR_EXCEPTION(!srcMap->isSameAs(*(rhs.getSourceMap())), std::invalid_argument,
1340 "Tpetra::Import::setUnion: The source Map of the input Import must be the "
1341 "same as (in the sense of Map::isSameAs) the source Map of this Import.");
1342 const Comm<int>& comm1 = *(tgtMap1->getComm());
1343 const Comm<int>& comm2 = *(tgtMap2->getComm());
1345 std::invalid_argument,
1346 "Tpetra::Import::setUnion: "
1347 "The target Maps must have congruent communicators.");
1348 }
1349
1350 // It's probably worth the one all-reduce to check whether the two
1351 // Maps are the same. If so, we can just return a copy of *this.
1352 // isSameAs() bypasses the all-reduce if the pointers are equal.
1353 if (tgtMap1->isSameAs(*tgtMap2)) {
1354 return rcp(new import_type(*this));
1355 }
1356
1357 // Alas, the two target Maps are not the same. That means we have
1358 // to compute their union, and the union Import object.
1359
1360 // Get the same GIDs (same GIDs are a subview of the first numSame target
1361 // GIDs)
1362 const size_type numSameGIDs1 = this->getNumSameIDs();
1363 ArrayView<const GO> sameGIDs1 = (tgtMap1->getLocalElementList())(0, numSameGIDs1);
1364
1365 const size_type numSameGIDs2 = rhs.getNumSameIDs();
1366 ArrayView<const GO> sameGIDs2 = (tgtMap2->getLocalElementList())(0, numSameGIDs2);
1367
1368 // Get permute GIDs
1369 ArrayView<const LO> permuteToLIDs1 = this->getPermuteToLIDs();
1371 for (size_type k = 0; k < permuteGIDs1.size(); k++)
1372 permuteGIDs1[k] = tgtMap1->getGlobalElement(permuteToLIDs1[k]);
1373
1374 ArrayView<const LO> permuteToLIDs2 = rhs.getPermuteToLIDs();
1376 for (size_type k = 0; k < permuteGIDs2.size(); k++)
1377 permuteGIDs2[k] = tgtMap2->getGlobalElement(permuteToLIDs2[k]);
1378
1379 // Get remote GIDs
1380 ArrayView<const LO> remoteLIDs1 = this->getRemoteLIDs();
1382 for (size_type k = 0; k < remoteLIDs1.size(); k++)
1383 remoteGIDs1[k] = this->getTargetMap()->getGlobalElement(remoteLIDs1[k]);
1384
1385 ArrayView<const LO> remoteLIDs2 = rhs.getRemoteLIDs();
1387 for (size_type k = 0; k < remoteLIDs2.size(); k++)
1388 remoteGIDs2[k] = rhs.getTargetMap()->getGlobalElement(remoteLIDs2[k]);
1389
1390 // Get remote PIDs
1392 Tpetra::Import_Util::getRemotePIDs(*this, remotePIDs1);
1393
1395 Tpetra::Import_Util::getRemotePIDs(rhs, remotePIDs2);
1396
1397 // Get the union of the target GIDs
1401
1402 findUnionTargetGIDs(unionTgtGIDs, remotePGIDs,
1406
1407 // Extract GIDs and compute LIDS, PIDs for the remotes in the union
1412 for (size_type k = 0; k < numRemoteIDsUnion; ++k) {
1414 remotePIDsUnion[k] = remotePGIDs[k].first;
1415 remoteGIDsUnion[k] = remotePGIDs[k].second;
1416 }
1417
1418 // Compute the permute-to LIDs (in the union target Map).
1419 // Convert the permute GIDs to permute-from LIDs in the source Map.
1422
1423 for (size_type k = 0; k < numPermuteIDsUnion; ++k) {
1424 size_type idx = numSameIDsUnion + k;
1425 permuteToLIDsUnion[k] = static_cast<LO>(idx);
1426 permuteFromLIDsUnion[k] = srcMap->getLocalElement(unionTgtGIDs[idx]);
1427 }
1428
1429 MM = Teuchos::null;
1430 auto MM2 = Teuchos::rcp(new Tpetra::Details::ProfilingRegion("Tpetra::Import::setUnion : Construct Target Map"));
1431
1432 // Create the union target Map.
1433 const GST INVALID = Teuchos::OrdinalTraits<GST>::invalid();
1434 const GO indexBaseUnion = std::min(tgtMap1->getIndexBase(), tgtMap2->getIndexBase());
1437
1438 MM2 = Teuchos::null;
1439 auto MM3 = Teuchos::rcp(new Tpetra::Details::ProfilingRegion("Tpetra::Import::setUnion : Export GIDs"));
1440
1441 // Thus far, we have computed the following in the union Import:
1442 // - numSameIDs
1443 // - numPermuteIDs and permuteFromLIDs
1444 // - numRemoteIDs, remoteGIDs, remoteLIDs, and remotePIDs
1445 //
1446 // Now it's time to compute the export IDs and initialize the
1447 // Distributor.
1448
1452 Distributor distributor(comm, this->TransferData_->out_);
1453
1454#ifdef TPETRA_IMPORT_SETUNION_USE_CREATE_FROM_SENDS
1455 // Compute the export IDs without communication, by merging the
1456 // lists of (export LID, export PID) pairs from the two input
1457 // Import objects. The export LIDs in both input Import objects
1458 // are LIDs in the source Map. Then, use the export PIDs to
1459 // initialize the Distributor via createFromSends.
1460
1461 // const size_type numExportIDs1 = this->getNumExportIDs ();
1462 ArrayView<const LO> exportLIDs1 = this->getExportLIDs();
1463 ArrayView<const LO> exportPIDs1 = this->getExportPIDs();
1464
1465 // const size_type numExportIDs2 = rhs.getNumExportIDs ();
1466 ArrayView<const LO> exportLIDs2 = rhs.getExportLIDs();
1467 ArrayView<const LO> exportPIDs2 = rhs.getExportPIDs();
1468
1469 // We have to keep the export LIDs in PID-sorted order, then merge
1470 // them. So, first key-value merge (LID,PID) pairs, treating PIDs
1471 // as values, merging values by replacement. Then, sort the
1472 // (LID,PID) pairs again by PID.
1473
1474 // Sort (LID,PID) pairs by LID for the later merge, and make
1475 // each sequence unique by LID.
1478 sort2(exportLIDs1Copy.begin(), exportLIDs1Copy.end(),
1479 exportPIDs1Copy.begin());
1486
1489 sort2(exportLIDs2Copy.begin(), exportLIDs2Copy.end(),
1490 exportPIDs2Copy.begin());
1497
1498 // Merge export (LID,PID) pairs. In this merge operation, the
1499 // LIDs are the "keys" and the PIDs their "values." We combine
1500 // the "values" (PIDs) in the pairs by replacement, rather than
1501 // by adding them together.
1503 exportPIDs1Copy.begin(), exportPIDs1Copy.end(),
1504 exportLIDs2Copy.begin(), exportLIDs2Copy.end(),
1505 exportPIDs2Copy.begin(), exportPIDs2Copy.end(),
1506 std::back_inserter(exportLIDsUnion),
1507 std::back_inserter(exportPIDsUnion),
1509
1510 // Resort the merged (LID,PID) pairs by PID.
1511 sort2(exportPIDsUnion.begin(), exportPIDsUnion.end(),
1512 exportLIDsUnion.begin());
1513
1514 // Initialize the Distributor. Using createFromSends instead of
1515 // createFromRecvs avoids the initialization and use of a
1516 // temporary Distributor object.
1517 (void)distributor.createFromSends(exportPIDsUnion().getConst());
1518#else // NOT TPETRA_IMPORT_SETUNION_USE_CREATE_FROM_SENDS
1519
1520 // Call the Distributor's createFromRecvs() method to turn the
1521 // remote GIDs and their owning processes into a send-and-receive
1522 // communication plan. remoteGIDsUnion and remotePIDsUnion are
1523 // input; exportGIDsUnion and exportPIDsUnion are output arrays
1524 // which are allocated by createFromRecvs().
1525 distributor.createFromRecvs(remoteGIDsUnion().getConst(),
1526 remotePIDsUnion().getConst(),
1528
1529 // Find the (source Map) LIDs corresponding to the export GIDs.
1530 const size_type numExportIDsUnion = exportGIDsUnion.size();
1532 for (size_type k = 0; k < numExportIDsUnion; ++k) {
1533 exportLIDsUnion[k] = srcMap->getLocalElement(exportGIDsUnion[k]);
1534 }
1535#endif // TPETRA_IMPORT_SETUNION_USE_CREATE_FROM_SENDS
1536
1537 // Create and return the union Import. This uses the "expert" constructor
1538 MM3 = Teuchos::null;
1539 auto MM4 = Teuchos::rcp(new Tpetra::Details::ProfilingRegion("Tpetra::Import::setUnion : Construct Import"));
1541 rcp(new import_type(srcMap, unionTgtMap,
1546 this->TransferData_->out_));
1547 return unionImport;
1548}
1549
1550template <class LocalOrdinal, class GlobalOrdinal, class Node>
1551Teuchos::RCP<const Import<LocalOrdinal, GlobalOrdinal, Node>>
1553 setUnion(const Teuchos::RCP<Teuchos::ParameterList>& params) const {
1554 using Teuchos::Array;
1555 using Teuchos::ArrayView;
1556 using Teuchos::as;
1557 using Teuchos::Comm;
1558 using Teuchos::outArg;
1559 using Teuchos::RCP;
1560 using Teuchos::rcp;
1561 using Teuchos::REDUCE_MIN;
1562 using Teuchos::reduceAll;
1563 typedef LocalOrdinal LO;
1564 typedef GlobalOrdinal GO;
1565 Teuchos::RCP<const Import<LocalOrdinal, GlobalOrdinal, Node>> unionImport;
1566 RCP<const map_type> srcMap = this->getSourceMap();
1567 RCP<const map_type> tgtMap = this->getTargetMap();
1568 RCP<const Comm<int>> comm = srcMap->getComm();
1569
1570 ArrayView<const GO> srcGIDs = srcMap->getLocalElementList();
1571 ArrayView<const GO> tgtGIDs = tgtMap->getLocalElementList();
1572
1573 // All elements in srcMap will be in the "new" target map, so...
1574 size_t numSameIDsNew = srcMap->getLocalNumElements();
1575 size_t numRemoteIDsNew = this->getNumRemoteIDs();
1576 Array<LO> permuteToLIDsNew, permuteFromLIDsNew; // empty on purpose
1577
1578 // Grab some old data
1579 ArrayView<const LO> remoteLIDsOld = this->getRemoteLIDs();
1580 ArrayView<const LO> exportLIDsOld = this->getExportLIDs();
1581
1582 // Build up the new map (same part)
1584 for (size_t i = 0; i < numSameIDsNew; i++)
1585 GIDs[i] = srcGIDs[i];
1586
1587 // Build up the new map (remote part) and remotes list
1589 for (size_t i = 0; i < numRemoteIDsNew; i++) {
1592 }
1593
1594 // Build the new target map
1595 GO GO_INVALID = Teuchos::OrdinalTraits<GO>::invalid();
1597 rcp(new map_type(GO_INVALID, GIDs, tgtMap->getIndexBase(),
1598 tgtMap->getComm(), params));
1599
1600 // Exports are trivial (since the sourcemap doesn't change)
1601 Array<int> exportPIDsnew(this->getExportPIDs());
1602 Array<LO> exportLIDsnew(this->getExportLIDs());
1603
1604 // Copy the Distributor (due to how the Import constructor works)
1605 Distributor D(this->getDistributor());
1606
1607 // Build the importer using the "expert" constructor
1615 exportPIDsnew, D));
1616
1617 return unionImport;
1618}
1619
1620template <class LocalOrdinal, class GlobalOrdinal, class Node>
1621Teuchos::RCP<const Import<LocalOrdinal, GlobalOrdinal, Node>>
1623 createRemoteOnlyImport(const Teuchos::RCP<const map_type>& remoteTarget) const {
1624 using std::endl;
1625 using Teuchos::outArg;
1626 using Teuchos::rcp;
1627 using Teuchos::REDUCE_MIN;
1628 using Teuchos::reduceAll;
1629 using ::Tpetra::Details::Behavior;
1630 using ::Tpetra::Details::gathervPrint;
1631 using LO = LocalOrdinal;
1632 using GO = GlobalOrdinal;
1634
1635 const char funcPrefix[] = "Tpetra::createRemoteOnlyImport: ";
1636 int lclSuccess = 1;
1637 int gblSuccess = 1;
1638 const bool debug = Behavior::debug();
1639
1640 const size_t NumRemotes = this->getNumRemoteIDs();
1641 std::unique_ptr<std::string> procPrefix;
1642 Teuchos::RCP<const Teuchos::Comm<int>> comm;
1643 if (debug) {
1644 comm = remoteTarget.is_null() ? Teuchos::null : remoteTarget->getComm();
1645 std::ostringstream os;
1646 os << "Proc ";
1647 if (comm.is_null()) {
1648 os << "?";
1649 } else {
1650 os << comm->getRank();
1651 }
1652 os << ": ";
1653 procPrefix = std::unique_ptr<std::string>(new std::string(os.str()));
1654 }
1655
1656 if (debug) {
1657 std::ostringstream lclErr;
1658 if (remoteTarget.is_null()) {
1659 lclSuccess = -1;
1660 } else if (NumRemotes != remoteTarget->getLocalNumElements()) {
1661 lclSuccess = 0;
1662 lclErr << *procPrefix << "getNumRemoteIDs() = " << NumRemotes
1663 << " != remoteTarget->getLocalNumElements() = "
1664 << remoteTarget->getLocalNumElements() << "." << endl;
1665 }
1666
1667 if (comm.is_null()) {
1669 } else {
1671 }
1672 TEUCHOS_TEST_FOR_EXCEPTION(gblSuccess == -1, std::invalid_argument, funcPrefix << "Input target Map is null on at least one process.");
1673
1674 if (gblSuccess != 1) {
1675 if (comm.is_null()) {
1676 TEUCHOS_TEST_FOR_EXCEPTION(true, std::runtime_error, lclErr.str());
1677 } else {
1678 std::ostringstream gblErr;
1679 gblErr << funcPrefix << endl;
1680 gathervPrint(gblErr, lclErr.str(), *comm);
1681 TEUCHOS_TEST_FOR_EXCEPTION(true, std::runtime_error, gblErr.str());
1682 }
1683 }
1684 }
1685
1686 // Compute the new Remote LIDs
1687 Teuchos::ArrayView<const LO> oldRemoteLIDs = this->getRemoteLIDs();
1688 Teuchos::Array<LO> newRemoteLIDs(NumRemotes);
1689 const map_type& tgtMap = *(this->getTargetMap());
1690 size_t badCount = 0;
1691
1692 std::unique_ptr<std::vector<size_t>> badIndices;
1693 if (debug) {
1694 badIndices = std::unique_ptr<std::vector<size_t>>(new std::vector<size_t>);
1695 }
1696
1697 for (size_t i = 0; i < NumRemotes; ++i) {
1698 const LO oldLclInd = oldRemoteLIDs[i];
1699 if (oldLclInd == Teuchos::OrdinalTraits<LO>::invalid()) {
1700 ++badCount;
1701 if (debug) {
1702 badIndices->push_back(i);
1703 }
1704 continue;
1705 }
1706 const GO gblInd = tgtMap.getGlobalElement(oldLclInd);
1707 if (gblInd == Teuchos::OrdinalTraits<GO>::invalid()) {
1708 ++badCount;
1709 if (debug) {
1710 badIndices->push_back(i);
1711 }
1712 continue;
1713 }
1714 const LO newLclInd = remoteTarget->getLocalElement(gblInd);
1715 if (newLclInd == Teuchos::OrdinalTraits<LO>::invalid()) {
1716 ++badCount;
1717 if (debug) {
1718 badIndices->push_back(i);
1719 }
1720 continue;
1721 }
1723 // Now we make sure these guys are in sorted order (AztecOO-ML ordering)
1724 if (i > 0 && newRemoteLIDs[i] < newRemoteLIDs[i - 1]) {
1725 ++badCount;
1726 if (debug) {
1727 badIndices->push_back(i);
1728 }
1729 }
1730 }
1731
1732 if (badCount != 0) {
1733 lclSuccess = 0;
1734 }
1735
1736 if (debug) {
1737 if (comm.is_null()) {
1739 } else {
1741 }
1742 std::ostringstream lclErr;
1743 if (lclSuccess != 1) {
1744 lclErr << *procPrefix << "Count of bad indices: " << badCount
1745 << ", bad indices: [";
1746 // TODO (mfh 04 Sep 2019) Limit the maximum number of bad
1747 // indices to print.
1748 for (size_t k = 0; k < badCount; ++k) {
1749 const size_t badIndex = (*badIndices)[k];
1750 lclErr << "(" << badIndex << ","
1751 << oldRemoteLIDs[badIndex] << ")";
1752 if (k + size_t(1) < badCount) {
1753 lclErr << ", ";
1754 }
1755 }
1756 lclErr << "]" << endl;
1757 }
1758
1759 if (gblSuccess != 1) {
1760 std::ostringstream gblErr;
1761 gblErr << funcPrefix << "this->getRemoteLIDs() has \"bad\" "
1762 "indices on one or more processes. \"Bad\" means that the "
1763 "indices are invalid, they don't exist in the target Map, "
1764 "they don't exist in remoteTarget, or they are not in "
1765 "sorted order. In what follows, I will show the \"bad\" "
1766 "indices as (k, LID) pairs, where k is the zero-based "
1767 "index of the LID in this->getRemoteLIDs()."
1768 << endl;
1769 if (comm.is_null()) {
1770 gblErr << lclErr.str();
1771 } else {
1772 gathervPrint(gblErr, lclErr.str(), *comm);
1773 }
1774 TEUCHOS_TEST_FOR_EXCEPTION(true, std::runtime_error, gblErr.str());
1775 }
1776 } else { // not debug
1777 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);
1778 }
1779
1780 // Copy ExportPIDs and such
1781 // NOTE: Be careful: The "Expert" Import constructor we use does a "swap"
1782 // for most of the LID/PID lists and the Distributor, meaning it
1783 // ruins the existing object if we pass things in directly. Hence
1784 // we copy them first.
1785 Teuchos::Array<int> newExportPIDs(this->getExportPIDs());
1786 Teuchos::Array<LO> newExportLIDs(this->getExportLIDs());
1787 Teuchos::Array<LO> dummy;
1788 Distributor newDistor(this->getDistributor());
1789
1790 return rcp(new import_type(this->getSourceMap(), remoteTarget,
1791 static_cast<size_t>(0), dummy, dummy,
1794}
1795
1796} // namespace Tpetra
1797
1798#define TPETRA_IMPORT_CLASS_INSTANT(LO, GO, NODE) \
1799 template class Import<LO, GO, NODE>;
1800
1801// Explicit instantiation macro.
1802// Only invoke this when in the Tpetra namespace.
1803// Most users do not need to use this.
1804//
1805// LO: The local ordinal type.
1806// GO: The global ordinal type.
1807// NODE: The Kokkos Node type.
1808#define TPETRA_IMPORT_INSTANT(LO, GO, NODE) \
1809 TPETRA_IMPORT_CLASS_INSTANT(LO, GO, NODE)
1810
1811#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...
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.
Teuchos::RCP< const Import< LocalOrdinal, GlobalOrdinal, Node > > setUnion(const Import< LocalOrdinal, GlobalOrdinal, Node > &rhs, const Teuchos::RCP< Teuchos::ParameterList > &params=Teuchos::null) const
Return the union of this Import and rhs.
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.