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 <algorithm>
26#include <numeric>
27#include <vector>
29#include <memory>
30
31namespace Teuchos {
32template <class T>
33std::string toString(const std::vector<T>& x) {
34 std::ostringstream os;
35 os << "[";
36 const std::size_t N = x.size();
37 for (std::size_t k = 0; k < N; ++k) {
38 os << x[k];
39 if (k + std::size_t(1) < N) {
40 os << ",";
41 }
42 }
43 os << "]";
44 return os.str();
45}
46
47template <class ElementType, class DeviceType>
48std::string toString(const Kokkos::View<const ElementType*, DeviceType>& x) {
49 std::ostringstream os;
50 os << "[";
51 const std::size_t N = std::size_t(x.extent(0));
52 for (std::size_t k = 0; k < N; ++k) {
53 os << x[k];
54 if (k + std::size_t(1) < N) {
55 os << ",";
56 }
57 }
58 os << "]";
59 return os.str();
60}
61} // namespace Teuchos
62
63namespace Tpetra {
64
65// head: init(source, target, true, remotePIDs, Teuchos::null);
66
67template <class LocalOrdinal, class GlobalOrdinal, class Node>
68void Import<LocalOrdinal, GlobalOrdinal, Node>::
69 init(const Teuchos::RCP<const map_type>& source,
70 const Teuchos::RCP<const map_type>& /* target */,
71 bool useRemotePIDs,
72 Teuchos::Array<int>& remotePIDs,
73 const Teuchos::RCP<Teuchos::ParameterList>& plist) {
74 using std::endl;
75 using Teuchos::Array;
76 using Teuchos::null;
77 using Teuchos::Ptr;
78 using Teuchos::rcp;
79 using ::Tpetra::Details::ProfilingRegion;
80 ProfilingRegion regionImportInit("Tpetra::Import::init");
81
82 std::unique_ptr<std::string> verbPrefix;
83 if (this->verbose()) {
84 std::ostringstream os;
85 const int myRank = source->getComm()->getRank();
86 os << "Proc " << myRank << ": Tpetra::Import::init: ";
87 verbPrefix = std::unique_ptr<std::string>(new std::string(os.str()));
88 os << endl;
89 this->verboseOutputStream() << os.str();
90 }
91
92 Array<GlobalOrdinal> remoteGIDs;
93
94 {
95 Tpetra::Details::ProfilingRegion MM("Tpetra:iport_ctor:preIData");
96 if (this->verbose()) {
97 std::ostringstream os;
98 os << *verbPrefix << "Call setupSamePermuteRemote" << endl;
99 this->verboseOutputStream() << os.str();
100 }
101 setupSamePermuteRemote(remoteGIDs);
102 }
103 {
104 Tpetra::Details::ProfilingRegion MM2("Tpetra:iport_ctor:preSetupExport");
105 if (source->isDistributed()) {
106 if (this->verbose()) {
107 std::ostringstream os;
108 os << *verbPrefix << "Call setupExport" << endl;
109 this->verboseOutputStream() << os.str();
110 }
111 setupExport(remoteGIDs, useRemotePIDs, remotePIDs);
112 } else if (this->verbose()) {
113 std::ostringstream os;
114 os << *verbPrefix << "Source Map not distributed; skip setupExport"
115 << endl;
116 this->verboseOutputStream() << os.str();
117 }
118 }
119
120 TEUCHOS_ASSERT(!this->TransferData_->permuteFromLIDs_.need_sync_device());
121 TEUCHOS_ASSERT(!this->TransferData_->permuteFromLIDs_.need_sync_host());
122 TEUCHOS_ASSERT(!this->TransferData_->permuteToLIDs_.need_sync_device());
123 TEUCHOS_ASSERT(!this->TransferData_->permuteToLIDs_.need_sync_host());
124 TEUCHOS_ASSERT(!this->TransferData_->remoteLIDs_.need_sync_device());
125 TEUCHOS_ASSERT(!this->TransferData_->remoteLIDs_.need_sync_host());
126 TEUCHOS_ASSERT(!this->TransferData_->exportLIDs_.need_sync_device());
127 TEUCHOS_ASSERT(!this->TransferData_->exportLIDs_.need_sync_host());
128
129 this->detectRemoteExportLIDsContiguous();
130
131 if (this->verbose()) {
132 std::ostringstream os;
133 os << *verbPrefix << "Done!" << endl;
134 this->verboseOutputStream() << os.str();
135 }
136}
137
138template <class LocalOrdinal, class GlobalOrdinal, class Node>
140 Import(const Teuchos::RCP<const map_type>& source,
141 const Teuchos::RCP<const map_type>& target)
142 : base_type(source, target, Teuchos::null, Teuchos::null, "Import") {
143 Teuchos::Array<int> dummy;
144 init(source, target, false, dummy, Teuchos::null);
145}
146
147template <class LocalOrdinal, class GlobalOrdinal, class Node>
149 Import(const Teuchos::RCP<const map_type>& source,
150 const Teuchos::RCP<const map_type>& target,
151 const Teuchos::RCP<Teuchos::FancyOStream>& out)
152 : base_type(source, target, out, Teuchos::null, "Import") {
153 Teuchos::Array<int> dummy;
154 init(source, target, false, dummy, Teuchos::null);
155}
156
157template <class LocalOrdinal, class GlobalOrdinal, class Node>
159 Import(const Teuchos::RCP<const map_type>& source,
160 const Teuchos::RCP<const map_type>& target,
161 const Teuchos::RCP<Teuchos::ParameterList>& plist)
162 : base_type(source, target, Teuchos::null, plist, "Import") {
163 Teuchos::Array<int> dummy;
164 init(source, target, false, dummy, plist);
165}
166
167template <class LocalOrdinal, class GlobalOrdinal, class Node>
169 Import(const Teuchos::RCP<const map_type>& source,
170 const Teuchos::RCP<const map_type>& target,
171 const Teuchos::RCP<Teuchos::FancyOStream>& out,
172 const Teuchos::RCP<Teuchos::ParameterList>& plist)
173 : base_type(source, target, out, plist, "Import") {
174 Teuchos::Array<int> dummy;
175 init(source, target, false, dummy, plist);
176}
177
178template <class LocalOrdinal, class GlobalOrdinal, class Node>
180 Import(const Teuchos::RCP<const map_type>& source,
181 const Teuchos::RCP<const map_type>& target,
182 Teuchos::Array<int>& remotePIDs,
183 const Teuchos::RCP<Teuchos::ParameterList>& plist)
184 : base_type(source, target, Teuchos::null, plist, "Import") {
185 init(source, target, true, remotePIDs, plist);
186}
187
188template <class LocalOrdinal, class GlobalOrdinal, class Node>
192
193template <class LocalOrdinal, class GlobalOrdinal, class Node>
197
198// cblcbl
199// This is the "createExpert" version of the constructor to be used with pid/gid pairs obtained from
200// reverse communication
201template <class LocalOrdinal, class GlobalOrdinal, class Node>
203 Import(const Teuchos::RCP<const Map<LocalOrdinal, GlobalOrdinal, Node>>& source,
204 const Teuchos::RCP<const Map<LocalOrdinal, GlobalOrdinal, Node>>& target,
205 const Teuchos::ArrayView<int>& userRemotePIDs,
206 const Teuchos::ArrayView<const LocalOrdinal>& userExportLIDs,
207 const Teuchos::ArrayView<const int>& userExportPIDs,
208 const Teuchos::RCP<Teuchos::ParameterList>& plist,
209 const Teuchos::RCP<Teuchos::FancyOStream>& out)
210 : base_type(source, target, out, plist, "Import") {
211 using std::endl;
212 using Teuchos::arcp;
213 using Teuchos::Array;
214 using Teuchos::ArrayRCP;
215 using Teuchos::ArrayView;
216 using Teuchos::as;
217 using Teuchos::null;
218 using Teuchos::rcp;
219 using ::Tpetra::Details::makeDualViewFromArrayView;
220 using LO = LocalOrdinal;
221 using GO = GlobalOrdinal;
222 using size_type = Teuchos::Array<int>::size_type;
223
224 std::unique_ptr<std::string> prefix;
225 if (this->verbose()) {
226 auto comm = source.is_null() ? Teuchos::null : source->getComm();
227 const int myRank = comm.is_null() ? -1 : comm->getRank();
228 std::ostringstream os;
229 os << "Proc " << myRank << ": Tpetra::Import createExpert ctor: ";
230 prefix = std::unique_ptr<std::string>(new std::string(os.str()));
231 os << "Start" << endl;
232 this->verboseOutputStream() << os.str();
233 }
234
235 ArrayView<const GO> sourceGIDs = source->getLocalElementList();
236 ArrayView<const GO> targetGIDs = target->getLocalElementList();
237
239 if (this->verbose()) {
240 std::ostringstream os;
241 os << *prefix << "Call setupSamePermuteRemote" << endl;
242 this->verboseOutputStream() << os.str();
243 }
244 setupSamePermuteRemote(tRemoteGIDs);
245
246 if (this->verbose()) {
247 std::ostringstream os;
248 os << *prefix << "Sort & filter IDs" << endl;
249 this->verboseOutputStream() << os.str();
250 }
251
252 auto tRemoteLIDs = this->TransferData_->remoteLIDs_.view_host();
253 this->TransferData_->remoteLIDs_.modify_host();
254 Teuchos::Array<int> tRemotePIDs(userRemotePIDs);
255
256 if (this->verbose() && this->getNumRemoteIDs() > 0 && !source->isDistributed()) {
257 std::ostringstream os;
258 os << *prefix << "Target Map has remote LIDs but source Map is not "
259 "distributed. Importing to a submap of the target Map."
260 << endl;
261 this->verboseOutputStream() << os.str();
262 }
263 // FIXME (mfh 03 Feb 2019) I don't see this as "abuse"; it's
264 // perfectly valid Petra Object Model behavior.
265 TPETRA_ABUSE_WARNING(getNumRemoteIDs() > 0 && !source->isDistributed(),
266 std::runtime_error,
267 "::constructExpert: Target Map has remote LIDs but source Map "
268 "is not distributed. Importing to a submap of the target Map.");
270 size_t(tRemoteGIDs.size()) != size_t(tRemoteLIDs.extent(0)),
271 std::runtime_error,
272 "Import::Import createExpert version: "
273 "Size mismatch on userRemotePIDs, remoteGIDs, and remoteLIDs "
274 "Array's to sort3.");
275
276 sort3(tRemotePIDs.begin(),
277 tRemotePIDs.end(),
278 tRemoteGIDs.begin(),
279 tRemoteLIDs.data());
280
281 // Get rid of IDs that don't exist in SourceMap
282 size_type cnt = 0;
283 size_type indexIntoRemotePIDs = tRemotePIDs.size();
284 for (size_type i = 0; i < indexIntoRemotePIDs; ++i) {
285 if (tRemotePIDs[i] == -1) {
286 ++cnt;
287 }
288 }
289
290 if (cnt == 0) { // done modifying remoteLIDs_
291 this->TransferData_->remoteLIDs_.sync_device();
292 } else {
293 if (indexIntoRemotePIDs - cnt > 0) {
297 cnt = 0;
298
299 for (size_type j = 0; j < indexIntoRemotePIDs; ++j)
300 if (tRemotePIDs[j] != -1) {
303 newRemoteLIDs[cnt] = target->getLocalElement(tRemoteGIDs[j]);
304 ++cnt;
305 }
309 makeDualViewFromArrayView(this->TransferData_->remoteLIDs_,
310 newRemoteLIDs().getConst(),
311 "remoteLIDs");
312 } else { // valid RemoteIDs empty
314 tRemoteGIDs.clear();
315 tRemotePIDs.clear();
316 this->TransferData_->remoteLIDs_ = decltype(this->TransferData_->remoteLIDs_)();
317 }
318 }
319
320 this->TransferData_->exportPIDs_ = Teuchos::Array<int>(userExportPIDs);
321 makeDualViewFromArrayView(this->TransferData_->exportLIDs_,
322 userExportLIDs, "exportLIDs");
323
324 bool locallyComplete = true;
325 for (size_type i = 0; i < userExportPIDs.size() && locallyComplete; ++i) {
326 if (userExportPIDs[i] == -1) {
327 locallyComplete = false;
328 }
329 }
330 this->TransferData_->isLocallyComplete_ = locallyComplete;
331
332 if (this->verbose()) {
333 std::ostringstream os;
334 os << *prefix << "locallyComplete: "
335 << (locallyComplete ? "true" : "false")
336 << "; call createFromSendsAndRecvs" << endl;
337 this->verboseOutputStream() << os.str();
338 }
339 {
340 Tpetra::Details::ProfilingRegion MM3("Tpetra:iport_ctor:cFSAR ");
341 Distributor& distributor = this->TransferData_->distributor_;
342 distributor.createFromSendsAndRecvs(this->TransferData_->exportPIDs_, tRemotePIDs);
343 }
344
345 this->detectRemoteExportLIDsContiguous();
346
347 TEUCHOS_ASSERT(!this->TransferData_->permuteFromLIDs_.need_sync_device());
348 TEUCHOS_ASSERT(!this->TransferData_->permuteFromLIDs_.need_sync_host());
349 TEUCHOS_ASSERT(!this->TransferData_->permuteToLIDs_.need_sync_device());
350 TEUCHOS_ASSERT(!this->TransferData_->permuteToLIDs_.need_sync_host());
351 TEUCHOS_ASSERT(!this->TransferData_->remoteLIDs_.need_sync_device());
352 TEUCHOS_ASSERT(!this->TransferData_->remoteLIDs_.need_sync_host());
353 TEUCHOS_ASSERT(!this->TransferData_->exportLIDs_.need_sync_device());
354 TEUCHOS_ASSERT(!this->TransferData_->exportLIDs_.need_sync_host());
355}
356
357template <class LocalOrdinal, class GlobalOrdinal, class Node>
359 Import(const Teuchos::RCP<const map_type>& source,
360 const Teuchos::RCP<const map_type>& target,
361 const size_t numSameIDs,
362 Teuchos::Array<LocalOrdinal>& permuteToLIDs,
363 Teuchos::Array<LocalOrdinal>& permuteFromLIDs,
364 Teuchos::Array<LocalOrdinal>& remoteLIDs,
365 Teuchos::Array<LocalOrdinal>& exportLIDs,
366 Teuchos::Array<int>& exportPIDs,
368 const Teuchos::RCP<Teuchos::FancyOStream>& out,
369 const Teuchos::RCP<Teuchos::ParameterList>& plist)
370 : base_type(source, target, out, plist, "Import") {
371 using std::endl;
372 using ::Tpetra::Details::makeDualViewFromArrayView;
373
374 std::unique_ptr<std::string> prefix;
375 if (this->verbose()) {
376 auto comm = source.is_null() ? Teuchos::null : source->getComm();
377 const int myRank = comm.is_null() ? -1 : comm->getRank();
378 std::ostringstream os;
379 os << "Proc " << myRank << ": Tpetra::Import export ctor: ";
380 prefix = std::unique_ptr<std::string>(new std::string(os.str()));
381 os << "Start" << endl;
382 this->verboseOutputStream() << os.str();
383 }
384
385 bool locallyComplete = true;
386 for (Teuchos::Array<int>::size_type i = 0; i < exportPIDs.size(); ++i) {
387 if (exportPIDs[i] == -1) {
388 locallyComplete = false;
389 }
390 }
391 if (this->verbose()) {
392 std::ostringstream os;
393 os << *prefix << "numSameIDs: " << numSameIDs << ", locallyComplete: "
394 << (locallyComplete ? "true" : "false") << endl;
395 this->verboseOutputStream() << os.str();
396 }
397
398 this->TransferData_->isLocallyComplete_ = locallyComplete;
399 this->TransferData_->numSameIDs_ = numSameIDs;
400
401 makeDualViewFromArrayView(this->TransferData_->permuteToLIDs_,
402 permuteToLIDs().getConst(),
403 "permuteToLIDs");
404 TEUCHOS_ASSERT(size_t(this->TransferData_->permuteToLIDs_.extent(0)) ==
405 size_t(permuteToLIDs.size()));
406 makeDualViewFromArrayView(this->TransferData_->permuteFromLIDs_,
407 permuteFromLIDs().getConst(),
408 "permuteFromLIDs");
409 TEUCHOS_ASSERT(size_t(this->TransferData_->permuteFromLIDs_.extent(0)) ==
410 size_t(permuteFromLIDs.size()));
411 makeDualViewFromArrayView(this->TransferData_->remoteLIDs_,
412 remoteLIDs().getConst(),
413 "remoteLIDs");
414 TEUCHOS_ASSERT(size_t(this->TransferData_->remoteLIDs_.extent(0)) ==
415 size_t(remoteLIDs.size()));
416 makeDualViewFromArrayView(this->TransferData_->exportLIDs_,
417 exportLIDs().getConst(),
418 "exportLIDs");
419 TEUCHOS_ASSERT(size_t(this->TransferData_->exportLIDs_.extent(0)) ==
420 size_t(exportLIDs.size()));
421 this->TransferData_->exportPIDs_.swap(exportPIDs);
422 this->TransferData_->distributor_.swap(distributor);
423
424 this->detectRemoteExportLIDsContiguous();
425
426 TEUCHOS_ASSERT(!this->TransferData_->permuteFromLIDs_.need_sync_device());
427 TEUCHOS_ASSERT(!this->TransferData_->permuteFromLIDs_.need_sync_host());
428 TEUCHOS_ASSERT(!this->TransferData_->permuteToLIDs_.need_sync_device());
429 TEUCHOS_ASSERT(!this->TransferData_->permuteToLIDs_.need_sync_host());
430 TEUCHOS_ASSERT(!this->TransferData_->remoteLIDs_.need_sync_device());
431 TEUCHOS_ASSERT(!this->TransferData_->remoteLIDs_.need_sync_host());
432 TEUCHOS_ASSERT(!this->TransferData_->exportLIDs_.need_sync_device());
433 TEUCHOS_ASSERT(!this->TransferData_->exportLIDs_.need_sync_host());
434}
435
436namespace { // (anonymous)
437
438template <class LO, class GO, class NT>
439struct ImportLocalSetupResult {
440 Teuchos::RCP<const ::Tpetra::Map<LO, GO, NT>> targetMap;
441 LO numSameIDs;
442 // std::vector<LO> permuteToLIDs; // users aren't supposed to have permutes
443 // std::vector<LO> permuteFromLIDs; // users aren't suppoosed to have permutes
444 std::vector<GO> remoteGIDs;
445 std::vector<LO> remoteLIDs;
446 std::vector<int> remotePIDs;
447 LO numPermutes; // users aren't supposed to have permutes
448};
449
450template <class T>
451void printArray(std::ostream& out, const T x[], const std::size_t N) {
452 out << "[";
453 for (std::size_t k = 0; k < N; ++k) {
454 out << x[k];
455 if (k + 1 < N) {
456 out << ", ";
457 }
458 }
459 out << "]";
460}
461
462template <class LO, class GO, class NT>
463ImportLocalSetupResult<LO, GO, NT>
464setupSamePermuteRemoteFromUserGlobalIndexList(const ::Tpetra::Map<LO, GO, NT>& sourceMap,
465 const GO targetMapRemoteOrPermuteGlobalIndices[],
466 const int targetMapRemoteOrPermuteProcessRanks[],
467 const LO numTargetMapRemoteOrPermuteGlobalIndices,
468 const bool mayReorderTargetMapIndicesLocally,
469 Teuchos::FancyOStream* out, // only valid if verbose
470 const std::string* verboseHeader, // only valid if verbose
471 const bool verbose,
472 const bool debug) {
473 using std::endl;
474 const int myRank = sourceMap.getComm()->getRank();
475 ImportLocalSetupResult<LO, GO, NT> result;
476
477 if (verbose) {
478 std::ostringstream os;
479 os << *verboseHeader << "- Import::setupSPR w/ remote GIDs & PIDs: " << endl
480 << *verboseHeader << " Input GIDs: ";
481 printArray(os, targetMapRemoteOrPermuteGlobalIndices, numTargetMapRemoteOrPermuteGlobalIndices);
482 os << endl
483 << " Input PIDs: ";
484 printArray(os, targetMapRemoteOrPermuteProcessRanks, numTargetMapRemoteOrPermuteGlobalIndices);
485 os << endl;
486 *out << os.str();
487 }
488
489 // In debug mode, check whether any of the input GIDs are
490 // actually in the source Map on the calling process. That's an
491 // error, because it means duplicate GIDs on the calling
492 // process. Also check if any of the input PIDs are invalid.
493 if (debug) {
494 std::vector<GO> badGIDs;
495 std::vector<int> badPIDs;
496 const Teuchos::Comm<int>& comm = *(sourceMap.getComm());
497 const int numProcs = comm.getSize();
498
499 for (LO k = 0; k < numTargetMapRemoteOrPermuteGlobalIndices; ++k) {
500 const GO tgtGID = targetMapRemoteOrPermuteGlobalIndices[k];
501 if (sourceMap.isNodeGlobalElement(tgtGID)) {
502 badGIDs.push_back(tgtGID);
503 }
504 const int tgtPID = targetMapRemoteOrPermuteProcessRanks[k];
505 if (tgtPID < 0 || tgtPID >= numProcs) {
506 badPIDs.push_back(tgtPID);
507 }
508 }
509
510 std::array<int, 2> lclStatus{{badGIDs.size() == 0 ? 1 : 0,
511 badPIDs.size() == 0 ? 1 : 0}};
512 std::array<int, 2> gblStatus{{0, 0}}; // output argument
513 Teuchos::reduceAll<int, int>(comm, Teuchos::REDUCE_MIN, 2,
514 lclStatus.data(), gblStatus.data());
515 const bool good = gblStatus[0] == 1 && gblStatus[1] == 1;
516 // Don't actually print all the "bad" GIDs and/or PIDs unless
517 // in verbose mode, since there could be many of them.
518 if (verbose && gblStatus[0] != 1) {
519 std::ostringstream os;
520 os << *verboseHeader << "- Some input GIDs are already in the source Map: ";
521 printArray(os, badGIDs.data(), badGIDs.size());
522 os << endl;
523 ::Tpetra::Details::gathervPrint(*out, os.str(), comm);
524 }
525 if (verbose && gblStatus[0] != 1) {
526 std::ostringstream os;
527 os << *verboseHeader << "- Some input PIDs are invalid: ";
528 printArray(os, badPIDs.data(), badPIDs.size());
529 os << endl;
530 ::Tpetra::Details::gathervPrint(*out, os.str(), comm);
531 }
532
533 if (!good) {
534 std::ostringstream os;
535 os << "Tpetra::Import constructor that takes remote GIDs and PIDs: ";
536 if (gblStatus[0] != 1) {
537 os << "Some input GIDs (global indices) are already in the source Map! ";
538 }
539 if (gblStatus[1] != 1) {
540 os << "Some input PIDs (process ranks) are invalid! ";
541 }
542 os << "Rerun with the environment variable TPETRA_VERBOSE=Tpetra::Import "
543 "to see what GIDs and/or PIDs are bad.";
544 TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument, os.str());
545 }
546 }
547
548 // Create list of GIDs to go into target Map. We need to copy
549 // the GIDs into this list anyway, so once we have them, we can
550 // sort the "remotes" in place.
551 const LO numLclSrcIDs = static_cast<LO>(sourceMap.getLocalNumElements());
552 const LO numLclTgtIDs = numLclSrcIDs + numTargetMapRemoteOrPermuteGlobalIndices;
553 if (verbose) {
554 std::ostringstream os;
555 os << *verboseHeader << "- Copy source Map GIDs into target Map GID list: "
556 "numLclSrcIDs="
557 << numLclSrcIDs
558 << ", numTargetMapRemoteOrPermuteGlobalIndices="
559 << numTargetMapRemoteOrPermuteGlobalIndices << endl;
560 *out << os.str();
561 }
562 std::vector<GO> tgtGIDs(numLclTgtIDs); // will go into target Map ctor
563 if (sourceMap.isContiguous()) {
564 GO curTgtGID = sourceMap.getMinGlobalIndex();
565 for (LO k = 0; k < numLclSrcIDs; ++k, ++curTgtGID) {
566 tgtGIDs[k] = curTgtGID;
567 }
568 } else { // avoid calling getLocalElementList on a contiguous Map
569 auto srcGIDs = sourceMap.getLocalElementList(); // Teuchos::ArrayView has a different
570 for (LO k = 0; k < numLclSrcIDs; ++k) { // iterator type, so can't std::copy
571 tgtGIDs[k] = srcGIDs[k];
572 }
573 }
574 std::copy(targetMapRemoteOrPermuteGlobalIndices,
575 targetMapRemoteOrPermuteGlobalIndices + numTargetMapRemoteOrPermuteGlobalIndices,
576 tgtGIDs.begin() + numLclSrcIDs);
577
578 // Optionally, sort input by process rank, so that remotes
579 // coming from the same process are grouped together. Only sort
580 // remote GIDs. While doing so, detect permutes (input "remote"
581 // GIDs whose rank is the same as that of the calling process).
582 //
583 // Permutes are actually an error. We normally detect them in
584 // debug mode, but if we sort, we have a nearly free opportunity
585 // to do so. We may also safely ignore permutes as duplicates.
586 //
587 // NOTE: tgtPIDs only includes remotes, not source Map entries.
588 if (verbose) {
589 std::ostringstream os;
590 os << *verboseHeader << "- Sort by PID? "
591 << (mayReorderTargetMapIndicesLocally ? "true" : "false") << endl;
592 *out << os.str();
593 }
594 std::vector<int> tgtPIDs(targetMapRemoteOrPermuteProcessRanks,
595 targetMapRemoteOrPermuteProcessRanks + numTargetMapRemoteOrPermuteGlobalIndices);
596 result.numPermutes = 0;
597 if (mayReorderTargetMapIndicesLocally) {
598 Tpetra::sort2(tgtPIDs.begin(), tgtPIDs.end(), tgtGIDs.begin() + numLclSrcIDs);
599 auto range = std::equal_range(tgtPIDs.begin(), tgtPIDs.end(), myRank); // binary search
600 if (range.second > range.first) {
601 result.numPermutes = static_cast<LO>(range.second - range.first);
602 }
603 } else { // don't sort; linear search to count permutes
604 result.numPermutes = static_cast<LO>(std::count(tgtPIDs.begin(), tgtPIDs.end(), myRank));
605 }
606 // The _actual_ number of remotes.
607 const LO numRemotes = numTargetMapRemoteOrPermuteGlobalIndices - result.numPermutes;
608 result.numSameIDs = static_cast<LO>(sourceMap.getLocalNumElements());
609
610 if (verbose) {
611 std::ostringstream os;
612 os << *verboseHeader << "- numSame=" << result.numSameIDs
613 << ", numPermutes=" << result.numPermutes
614 << ", numRemotes=" << numRemotes << endl;
615 *out << os.str();
616 }
617
618 if (result.numPermutes == 0) {
619 if (verbose) {
620 std::ostringstream os;
621 os << *verboseHeader << "- No permutes" << endl;
622 *out << os.str();
623 }
624 result.remoteGIDs = std::vector<GO>(tgtGIDs.begin() + numLclSrcIDs, tgtGIDs.end());
625 result.remotePIDs.swap(tgtPIDs);
626 result.remoteLIDs.resize(numRemotes);
627 for (LO k = 0; k < numRemotes; ++k) {
628 const LO tgtLid = result.numSameIDs + k;
629 result.remoteLIDs[k] = tgtLid;
630 }
631 if (verbose) {
632 std::ostringstream os;
633 os << *verboseHeader << "- Remote GIDs: "
634 << Teuchos::toString(result.remoteGIDs) << endl;
635 os << *verboseHeader << "- Remote PIDs: "
636 << Teuchos::toString(result.remotePIDs) << endl;
637 os << *verboseHeader << "- Remote LIDs: "
638 << Teuchos::toString(result.remoteLIDs) << endl;
639 *out << os.str();
640 }
641 } else { // separate permutes from remotes
642 // This case doesn't need to be optimal; it just needs to be
643 // correct. Users really shouldn't give permutes to this
644 // Import constructor.
645 result.remoteGIDs.reserve(numRemotes);
646 result.remoteLIDs.reserve(numRemotes);
647 result.remotePIDs.reserve(numRemotes);
648 for (LO k = 0; k < numTargetMapRemoteOrPermuteGlobalIndices; ++k) {
649 const LO tgtLid = result.numSameIDs + k;
650 const GO tgtGid = tgtGIDs[numLclSrcIDs + k];
651 const int tgtPid = tgtPIDs[k];
652
653 if (tgtPid != myRank) { // it's a remote
654 result.remoteGIDs.push_back(tgtGid);
655 result.remoteLIDs.push_back(tgtLid);
656 result.remotePIDs.push_back(tgtPid);
657 }
658 }
659 if (verbose) {
660 std::ostringstream os;
661 os << *verboseHeader << "- Some permutes" << endl;
662 *out << os.str();
663 }
664 }
665
666 if (sourceMap.isDistributed()) {
667 if (verbose) {
668 std::ostringstream os;
669 os << *verboseHeader << "- Sort remotes by PID, as Import always does"
670 << endl
671 << *verboseHeader << "-- remotePIDs before: "
672 << Teuchos::toString(result.remotePIDs) << endl
673 << *verboseHeader << "-- remoteGIDs before: "
674 << Teuchos::toString(result.remoteGIDs) << endl
675 << *verboseHeader << "-- remoteLIDs before: "
676 << Teuchos::toString(result.remoteLIDs) << endl;
677 *out << os.str();
678 }
679 // Import always sorts these, regardless of what the user wanted.
680 sort3(result.remotePIDs.begin(),
681 result.remotePIDs.end(),
682 result.remoteGIDs.begin(),
683 result.remoteLIDs.begin());
684 if (verbose) {
685 std::ostringstream os;
686 os << *verboseHeader << "-- remotePIDs after: "
687 << Teuchos::toString(result.remotePIDs) << endl
688 << *verboseHeader << "-- remoteGIDs after: "
689 << Teuchos::toString(result.remoteGIDs) << endl
690 << *verboseHeader << "-- remoteLIDs after: "
691 << Teuchos::toString(result.remoteLIDs) << endl;
692 std::cerr << os.str();
693 }
694 }
695
696 if (verbose) {
697 std::ostringstream os;
698 os << *verboseHeader << "- Make target Map" << endl;
699 *out << os.str();
700 }
701 using ::Teuchos::rcp;
702 typedef ::Tpetra::Map<LO, GO, NT> map_type;
703 typedef ::Tpetra::global_size_t GST;
704 const GST MAP_COMPUTES_GLOBAL_COUNT = ::Teuchos::OrdinalTraits<GST>::invalid();
705 result.targetMap = rcp(new map_type(MAP_COMPUTES_GLOBAL_COUNT,
706 tgtGIDs.data(),
707 numLclTgtIDs,
708 sourceMap.getIndexBase(),
709 sourceMap.getComm()));
710 if (verbose) {
711 std::ostringstream os;
712 os << *verboseHeader << "- Done with sameSPR..." << endl;
713 *out << os.str();
714 }
715 return result;
716}
717} // namespace
718
719template <class LocalOrdinal, class GlobalOrdinal, class Node>
726 const Teuchos::RCP<Teuchos::ParameterList>& plist,
727 const Teuchos::RCP<Teuchos::FancyOStream>& debugOutput)
728 : // Special case: target Map is null on base_type construction.
729 // It's worthwhile for invariants like out_ not being null.
730 // We'll set TransferData_ again below.
731 base_type(sourceMap, Teuchos::null, debugOutput, plist, "Import") {
732 using std::endl;
733 using Teuchos::ArrayView;
734 using Teuchos::getFancyOStream;
735 using Teuchos::RCP;
736 using Teuchos::rcp;
737 using Teuchos::rcpFromRef;
738 using ::Tpetra::Details::Behavior;
739 using ::Tpetra::Details::makeDualViewFromOwningHostView;
740 using ::Tpetra::Details::makeDualViewFromVector;
741 using ::Tpetra::Details::printDualView;
742 using ::Tpetra::Details::view_alloc_no_init;
743 typedef LocalOrdinal LO;
744 typedef GlobalOrdinal GO;
745 typedef Node NT;
746
747 const bool debug = Behavior::debug("Import") ||
748 Behavior::debug("Tpetra::Import");
749
750 std::unique_ptr<std::string> verbPfx;
751 if (this->verbose()) {
752 std::ostringstream os;
753 const int myRank = sourceMap->getComm()->getRank();
754 os << "Proc " << myRank << ": Tpetra::Import ctor from remotes: ";
755 verbPfx = std::unique_ptr<std::string>(new std::string(os.str()));
756 os << "mayReorder=" << (mayReorderTargetMapIndicesLocally ? "true" : "false")
757 << endl;
758 this->verboseOutputStream() << os.str();
759 }
760
761 TEUCHOS_ASSERT(!this->TransferData_.is_null());
768 this->TransferData_->out_.getRawPtr(),
769 verbPfx.get(),
770 this->verbose(),
771 debug);
772
773 // Since we invoked the base_type constructor above, we know that
774 // out_ is nonnull, so we don't have to waste time creating it
775 // again.
777 TEUCHOS_ASSERT(!this->TransferData_.is_null());
779 localSetupResult.targetMap,
780 this->TransferData_->out_,
781 plist));
782 this->TransferData_->numSameIDs_ = localSetupResult.numSameIDs;
783 // Skip permutes; they are user error, because they duplicate
784 // non-remote indices.
785 makeDualViewFromVector(this->TransferData_->remoteLIDs_,
786 localSetupResult.remoteLIDs,
787 "remoteLIDs");
788 // "Is locally complete" for an Import means that all target Map
789 // indices on the calling process exist on at least one process
790 // (not necessarily this one) in the source Map. For this
791 // constructor, this is true if and only if all input target PIDs
792 // are valid PIDs in the communicator.
793 //
794 // FIXME (mfh 20 Feb 2018) For now, assume this is always true.
795 this->TransferData_->isLocallyComplete_ = true;
796
797 Teuchos::Array<GO> exportGIDs;
798 if (sourceMap->isDistributed()) {
799 if (this->verbose()) {
800 std::ostringstream os;
801 os << *verbPfx << "Make Distributor (createFromRecvs)" << endl;
802 this->verboseOutputStream() << os.str();
803 }
804 ArrayView<const GO> remoteGIDs(localSetupResult.remoteGIDs.data(),
805 localSetupResult.remoteGIDs.size());
806 ArrayView<const int> remotePIDs(localSetupResult.remotePIDs.data(),
807 localSetupResult.remotePIDs.size());
808 // Call Distributor::createFromRecvs to turn the remote GIDs and
809 // their owning PIDs into a send-and-receive communication plan.
810 // remoteGIDs and remotePIDs are input; exportGIDs and
811 // exportPIDs are output arrays that createFromRecvs allocates.
812 Distributor& distributor = this->TransferData_->distributor_;
813 distributor.createFromRecvs(remoteGIDs,
814 remotePIDs,
816 this->TransferData_->exportPIDs_);
817 // Find the LIDs corresponding to the (outgoing) GIDs in
818 // exportGIDs. For sparse matrix-vector multiply, this tells
819 // the calling process how to index into the source vector to
820 // get the elements which it needs to send.
821 //
822 // NOTE (mfh 03 Mar 2014) This is now a candidate for a
823 // thread-parallel kernel, but only if using the new thread-safe
824 // Map implementation.
825 if (this->verbose()) {
826 std::ostringstream os;
827 os << *verbPfx << "Compute exportLIDs" << endl;
828 this->verboseOutputStream() << os.str();
829 }
830 using size_type = typename Teuchos::Array<GO>::size_type;
831 const size_type numExportIDs = exportGIDs.size();
832
833 typename decltype(this->TransferData_->exportLIDs_)::t_host
834 exportLIDs(view_alloc_no_init("exportLIDs"), numExportIDs);
835
836 for (size_type k = 0; k < numExportIDs; ++k) {
837 exportLIDs[k] = sourceMap->getLocalElement(exportGIDs[k]);
838 }
839 makeDualViewFromOwningHostView(this->TransferData_->exportLIDs_, exportLIDs);
840 }
841
842 if (this->verbose()) {
843 std::ostringstream os;
844 os << *verbPfx;
845 printDualView(os, this->TransferData_->remoteLIDs_,
846 "ImportExportData::remoteLIDs_");
847 os << endl;
848 this->verboseOutputStream() << os.str();
849 }
850 if (this->verbose()) {
851 std::ostringstream os;
852 os << *verbPfx << "Done!" << endl;
853 this->verboseOutputStream() << os.str();
854 }
855}
856
857template <class LocalOrdinal, class GlobalOrdinal, class Node>
859 describe(Teuchos::FancyOStream& out,
860 const Teuchos::EVerbosityLevel verbLevel) const {
861 // Call the base class' method. It does all the work.
862 this->describeImpl(out, "Tpetra::Import", verbLevel);
863}
864
865template <class LocalOrdinal, class GlobalOrdinal, class Node>
867 print(std::ostream& os) const {
868 auto out = Teuchos::getFancyOStream(Teuchos::rcpFromRef(os));
869 // "Print" traditionally meant "everything."
870 this->describe(*out, Teuchos::VERB_EXTREME);
871}
872
873template <class LocalOrdinal, class GlobalOrdinal, class Node>
875 setupSamePermuteRemote(Teuchos::Array<GlobalOrdinal>& remoteGIDs) {
876 using Teuchos::arcp;
877 using Teuchos::Array;
878 using Teuchos::ArrayRCP;
879 using Teuchos::ArrayView;
880 using Teuchos::as;
881 using Teuchos::null;
882 using ::Tpetra::Details::makeDualViewFromOwningHostView;
883 using ::Tpetra::Details::ProfilingRegion;
884 using ::Tpetra::Details::view_alloc_no_init;
885 typedef LocalOrdinal LO;
886 typedef GlobalOrdinal GO;
887 typedef typename ArrayView<const GO>::size_type size_type;
888 ProfilingRegion regionExport("Tpetra::Import::setupSamePermuteRemote");
889
890 const map_type& source = *(this->getSourceMap());
891 const map_type& target = *(this->getTargetMap());
892 ArrayView<const GO> sourceGIDs = source.getLocalElementList();
893 ArrayView<const GO> targetGIDs = target.getLocalElementList();
894
895#ifdef HAVE_TPETRA_DEBUG
898#else
899 const GO* const rawSrcGids = sourceGIDs.getRawPtr();
900 const GO* const rawTgtGids = targetGIDs.getRawPtr();
901#endif // HAVE_TPETRA_DEBUG
902 const size_type numSrcGids = sourceGIDs.size();
903 const size_type numTgtGids = targetGIDs.size();
904 const size_type numGids = std::min(numSrcGids, numTgtGids);
905
906 // Compute numSameIDs_: the number of initial GIDs that are the
907 // same (and occur in the same order) in both Maps. The point of
908 // numSameIDs_ is for the common case of an Import where all the
909 // overlapping GIDs are at the end of the target Map, but
910 // otherwise the source and target Maps are the same. This allows
911 // a fast contiguous copy for the initial "same IDs."
912 size_type numSameGids = 0;
914 } // third clause of 'for' does everything
915 this->TransferData_->numSameIDs_ = numSameGids;
916
917 // Compute permuteToLIDs_, permuteFromLIDs_, remoteGIDs, and
918 // remoteLIDs_. The first two arrays are IDs to be permuted, and
919 // the latter two arrays are IDs to be received ("imported"),
920 // called "remote" IDs.
921 //
922 // IDs to permute are in both the source and target Maps, which
923 // means we don't have to send or receive them, but we do have to
924 // rearrange (permute) them in general. IDs to receive are in the
925 // target Map, but not the source Map.
926
927 // Iterate over the target Map's LIDs, since we only need to do
928 // GID -> LID lookups for the source Map.
929 const LO LINVALID = Teuchos::OrdinalTraits<LO>::invalid();
930 const LO numTgtLids = as<LO>(numTgtGids);
931 LO numPermutes = 0;
932
933 for (LO tgtLid = numSameGids; tgtLid < numTgtLids; ++tgtLid) {
934 const GO curTargetGid = rawTgtGids[tgtLid];
935 // getLocalElement() returns LINVALID if the GID isn't in the
936 // source Map. This saves us a lookup (which
937 // isNodeGlobalElement() would do).
938 const LO srcLid = source.getLocalElement(curTargetGid);
939 if (srcLid != LINVALID) { // if source.isNodeGlobalElement (curTargetGid)
940 ++numPermutes;
941 }
942 }
943 const LO numRemotes = (numTgtLids - numSameGids) - numPermutes;
944
945 using host_perm_type =
946 typename decltype(this->TransferData_->permuteToLIDs_)::t_host;
947 host_perm_type permuteToLIDs(view_alloc_no_init("permuteToLIDs"), numPermutes);
948 host_perm_type permuteFromLIDs(view_alloc_no_init("permuteFromLIDs"), numPermutes);
949 typename decltype(this->TransferData_->remoteLIDs_)::t_host remoteLIDs(view_alloc_no_init("permuteFromLIDs"), numRemotes);
950
951 {
952 LO numPermutes2 = 0;
953 LO numRemotes2 = 0;
954 for (LO tgtLid = numSameGids; tgtLid < numTgtLids; ++tgtLid) {
955 const GO curTargetGid = rawTgtGids[tgtLid];
956 const LO srcLid = source.getLocalElement(curTargetGid);
957 if (srcLid != LINVALID) {
958 permuteToLIDs[numPermutes2] = tgtLid;
959 permuteFromLIDs[numPermutes2] = srcLid;
960 ++numPermutes2;
961 } else {
962 remoteGIDs.push_back(curTargetGid);
963 remoteLIDs[numRemotes2] = tgtLid;
964 ++numRemotes2;
965 }
966 }
967 TEUCHOS_ASSERT(numPermutes == numPermutes2);
968 TEUCHOS_ASSERT(numRemotes == numRemotes2);
969 TEUCHOS_ASSERT(size_t(numPermutes) + remoteGIDs.size() == size_t(numTgtLids - numSameGids));
970 }
971
972 makeDualViewFromOwningHostView(this->TransferData_->permuteToLIDs_, permuteToLIDs);
973 makeDualViewFromOwningHostView(this->TransferData_->permuteFromLIDs_, permuteFromLIDs);
974 makeDualViewFromOwningHostView(this->TransferData_->remoteLIDs_, remoteLIDs);
975 if (remoteLIDs.extent(0) != 0 && !source.isDistributed()) {
976 // This Import has remote LIDs, meaning that the target Map has
977 // entries on this process that are not in the source Map on
978 // this process. However, the source Map is not distributed
979 // globally. This implies that this Import is not locally
980 // complete on this process.
981 this->TransferData_->isLocallyComplete_ = false;
982 // mfh 12 Sep 2016: I disagree that this is "abuse"; it may be
983 // correct behavior, depending on the circumstances.
984 TPETRA_ABUSE_WARNING(true, std::runtime_error,
985 "::setupSamePermuteRemote(): Target has "
986 "remote LIDs but Source is not distributed globally. Importing to a "
987 "submap of the target map.");
988 }
989}
990
991template <class LocalOrdinal, class GlobalOrdinal, class Node>
992void Import<LocalOrdinal, GlobalOrdinal, Node>::
993 setupExport(Teuchos::Array<GlobalOrdinal>& remoteGIDs,
994 bool useRemotePIDs,
995 Teuchos::Array<int>& userRemotePIDs,
996 const Teuchos::RCP<Teuchos::ParameterList>& plist) {
997 using std::endl;
998 using Teuchos::Array;
999 using Teuchos::ArrayView;
1000 using ::Tpetra::Details::makeDualViewFromOwningHostView;
1001 using ::Tpetra::Details::view_alloc_no_init;
1002 using GO = GlobalOrdinal;
1003 typedef typename Array<int>::difference_type size_type;
1004 const char tfecfFuncName[] = "setupExport: ";
1005 const char suffix[] = " Please report this bug to the Tpetra developers.";
1006
1007 std::unique_ptr<std::string> prefix;
1008 if (this->verbose()) {
1009 auto srcMap = this->getSourceMap();
1010 auto comm = srcMap.is_null() ? Teuchos::null : srcMap->getComm();
1011 const int myRank = comm.is_null() ? -1 : comm->getRank();
1012 std::ostringstream os;
1013 os << "Proc " << myRank << ": Tpetra::Import::setupExport: ";
1014 prefix = std::unique_ptr<std::string>(new std::string(os.str()));
1015 os << "Start" << std::endl;
1016 this->verboseOutputStream() << os.str();
1017 }
1018
1019 TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC(this->getSourceMap().is_null(), std::logic_error,
1020 "Source Map is null. " << suffix);
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 using Teuchos::Array;
1312 using Teuchos::ArrayView;
1313 using Teuchos::as;
1314 using Teuchos::Comm;
1315 using Teuchos::outArg;
1316 using Teuchos::RCP;
1317 using Teuchos::rcp;
1318 using Teuchos::REDUCE_MIN;
1319 using Teuchos::reduceAll;
1320 using ::Tpetra::Details::Behavior;
1321 using LO = LocalOrdinal;
1322 using GO = GlobalOrdinal;
1323 using import_type = Import<LO, GO, Node>;
1324 using size_type = typename Array<GO>::size_type;
1325
1326 Tpetra::Details::ProfilingRegion pr("Tpetra::Import::setUnion(rhs)");
1327
1328 RCP<const map_type> srcMap = this->getSourceMap();
1329 RCP<const map_type> tgtMap1 = this->getTargetMap();
1330 RCP<const map_type> tgtMap2 = rhs.getTargetMap();
1331 RCP<const Comm<int>> comm = srcMap->getComm();
1332
1333 const bool debug = Behavior::debug("Import::setUnion") ||
1334 Behavior::debug("Tpetra::Import::setUnion");
1335
1336 if (debug) {
1337 TEUCHOS_TEST_FOR_EXCEPTION(!srcMap->isSameAs(*(rhs.getSourceMap())), std::invalid_argument,
1338 "Tpetra::Import::setUnion: The source Map of the input Import must be the "
1339 "same as (in the sense of Map::isSameAs) the source Map of this Import.");
1340 const Comm<int>& comm1 = *(tgtMap1->getComm());
1341 const Comm<int>& comm2 = *(tgtMap2->getComm());
1343 std::invalid_argument,
1344 "Tpetra::Import::setUnion: "
1345 "The target Maps must have congruent communicators.");
1346 }
1347
1348 // It's probably worth the one all-reduce to check whether the two
1349 // Maps are the same. If so, we can just return a copy of *this.
1350 // isSameAs() bypasses the all-reduce if the pointers are equal.
1351 if (tgtMap1->isSameAs(*tgtMap2)) {
1352 return rcp(new import_type(*this));
1353 }
1354
1355 // Alas, the two target Maps are not the same. That means we have
1356 // to compute their union, and the union Import object.
1357
1367 std::shared_ptr<Details::CommRequest> req;
1368 {
1369 Tpetra::Details::ProfilingRegion prTgtMapLookups("Tpetra::Import::setUnion : Target Map lookups");
1370
1371 // Get the same GIDs (same GIDs are a subview of the first numSame target
1372 // GIDs)
1373 const size_type numSameGIDs1 = this->getNumSameIDs();
1374 ArrayView<const GO> sameGIDs1 = (tgtMap1->getLocalElementList())(0, numSameGIDs1);
1375
1376 const size_type numSameGIDs2 = rhs.getNumSameIDs();
1377 ArrayView<const GO> sameGIDs2 = (tgtMap2->getLocalElementList())(0, numSameGIDs2);
1378
1379 // Get permute GIDs
1380 ArrayView<const LO> permuteToLIDs1 = this->getPermuteToLIDs();
1382 for (size_type k = 0; k < permuteGIDs1.size(); k++)
1383 permuteGIDs1[k] = tgtMap1->getGlobalElement(permuteToLIDs1[k]);
1384
1385 ArrayView<const LO> permuteToLIDs2 = rhs.getPermuteToLIDs();
1387 for (size_type k = 0; k < permuteGIDs2.size(); k++)
1388 permuteGIDs2[k] = tgtMap2->getGlobalElement(permuteToLIDs2[k]);
1389
1390 // Get remote GIDs
1391 ArrayView<const LO> remoteLIDs1 = this->getRemoteLIDs();
1393 for (size_type k = 0; k < remoteLIDs1.size(); k++)
1394 remoteGIDs1[k] = this->getTargetMap()->getGlobalElement(remoteLIDs1[k]);
1395
1396 ArrayView<const LO> remoteLIDs2 = rhs.getRemoteLIDs();
1398 for (size_type k = 0; k < remoteLIDs2.size(); k++)
1399 remoteGIDs2[k] = rhs.getTargetMap()->getGlobalElement(remoteLIDs2[k]);
1400
1401 // Get remote PIDs
1403 Tpetra::Import_Util::getRemotePIDs(*this, remotePIDs1);
1404
1406 Tpetra::Import_Util::getRemotePIDs(rhs, remotePIDs2);
1407
1408 // Get the union of the target GIDs
1410 findUnionTargetGIDs(unionTgtGIDs, remotePGIDs,
1414 unionNumLocalElements = static_cast<global_size_t>(unionTgtGIDs.size());
1415 req = Details::iallreduce(unionNumLocalElements,
1416 unionNumGlobalElements, Teuchos::REDUCE_SUM, *comm);
1417
1418 // Extract GIDs and compute LIDS, PIDs for the remotes in the union
1423 for (size_type k = 0; k < numRemoteIDsUnion; ++k) {
1425 remotePIDsUnion[k] = remotePGIDs[k].first;
1426 remoteGIDsUnion[k] = remotePGIDs[k].second;
1427 }
1428
1429 // Compute the permute-to LIDs (in the union target Map).
1430 // Convert the permute GIDs to permute-from LIDs in the source Map.
1433
1434 for (size_type k = 0; k < numPermuteIDsUnion; ++k) {
1435 size_type idx = numSameIDsUnion + k;
1436 permuteToLIDsUnion[k] = static_cast<LO>(idx);
1437 permuteFromLIDsUnion[k] = srcMap->getLocalElement(unionTgtGIDs[idx]);
1438 }
1439 }
1440
1442 {
1443 // Create the union target Map.
1444 Tpetra::Details::ProfilingRegion prTgtMap("Tpetra::Import::setUnion : Construct Target Map");
1445 const GO indexBaseUnion = std::min(tgtMap1->getIndexBase(), tgtMap2->getIndexBase());
1446 req->wait();
1448 }
1449
1450 // Thus far, we have computed the following in the union Import:
1451 // - numSameIDs
1452 // - numPermuteIDs and permuteFromLIDs
1453 // - numRemoteIDs, remoteGIDs, remoteLIDs, and remotePIDs
1454 //
1455 // Now it's time to compute the export IDs and initialize the
1456 // Distributor.
1457
1460 Distributor distributor(comm, this->TransferData_->out_);
1461 {
1462 Tpetra::Details::ProfilingRegion prExportGIDs("Tpetra::Import::setUnion : Export GIDs");
1463
1464 const size_type numExportIDs1 = this->getNumExportIDs();
1465 const size_type numExportIDs2 = rhs.getNumExportIDs();
1466
1469
1470 if (numExportIDs1 + numExportIDs2 > 0) {
1471 auto exportLIDs1 = this->getExportLIDs();
1472 auto exportPIDs1 = this->getExportPIDs();
1473
1474 auto exportLIDs2 = rhs.getExportLIDs();
1475 auto exportPIDs2 = rhs.getExportPIDs();
1476
1477 std::copy(exportLIDs1.begin(), exportLIDs1.end(), exportLIDsUnion.begin());
1478 std::copy(exportLIDs2.begin(), exportLIDs2.end(), exportLIDsUnion.begin() + numExportIDs1);
1479
1480 std::copy(exportPIDs1.begin(), exportPIDs1.end(), exportPIDsUnion.begin());
1481 std::copy(exportPIDs2.begin(), exportPIDs2.end(), exportPIDsUnion.begin() + numExportIDs1);
1482
1483 std::vector<LO> idx(numExportIDs1 + numExportIDs2);
1484 std::iota(idx.begin(), idx.end(), 0);
1485 std::sort(idx.begin(), idx.end(), [&exportPIDsUnion, &exportLIDsUnion](const LO i1, const LO i2) { return (exportPIDsUnion[i1] == exportPIDsUnion[i2]) ? (exportLIDsUnion[i1] < exportLIDsUnion[i2]) : (exportPIDsUnion[i1] < exportPIDsUnion[i2]); });
1486
1487 Tpetra::SortDetails::apply_permutation(exportLIDsUnion.begin(), exportLIDsUnion.end(), idx);
1488 Tpetra::SortDetails::apply_permutation(exportPIDsUnion.begin(), exportPIDsUnion.end(), idx);
1489
1490 size_t knew = 0;
1491 for (size_type k = 1; k < numExportIDs1 + numExportIDs2; ++k) {
1493 ++knew;
1496 }
1497 }
1498 exportLIDsUnion.resize(knew + 1);
1499 exportPIDsUnion.resize(knew + 1);
1500 }
1501
1502 distributor.createFromSendsAndRecvs(exportPIDsUnion, remotePIDsUnion);
1503 }
1504
1506 {
1507 // Create and return the union Import. This uses the "expert" constructor
1508 Tpetra::Details::ProfilingRegion prImport("Tpetra::Import::setUnion : Construct Import");
1509 unionImport =
1510 rcp(new import_type(srcMap, unionTgtMap,
1515 this->TransferData_->out_));
1516 }
1517 return unionImport;
1518}
1519
1520template <class LocalOrdinal, class GlobalOrdinal, class Node>
1521Teuchos::RCP<const Import<LocalOrdinal, GlobalOrdinal, Node>>
1523 setUnion() const {
1524 using Teuchos::Array;
1525 using Teuchos::ArrayView;
1526 using Teuchos::as;
1527 using Teuchos::Comm;
1528 using Teuchos::outArg;
1529 using Teuchos::RCP;
1530 using Teuchos::rcp;
1531 using Teuchos::REDUCE_MIN;
1532 using Teuchos::reduceAll;
1533 typedef LocalOrdinal LO;
1534 typedef GlobalOrdinal GO;
1535
1536 Tpetra::Details::ProfilingRegion pr("Tpetra::Import::setUnion()");
1537
1538 Teuchos::RCP<const Import<LocalOrdinal, GlobalOrdinal, Node>> unionImport;
1539 RCP<const map_type> srcMap = this->getSourceMap();
1540 RCP<const map_type> tgtMap = this->getTargetMap();
1541 RCP<const Comm<int>> comm = srcMap->getComm();
1542
1543 ArrayView<const GO> srcGIDs = srcMap->getLocalElementList();
1544 ArrayView<const GO> tgtGIDs = tgtMap->getLocalElementList();
1545
1546 // All elements in srcMap will be in the "new" target map, so...
1547 size_t numSameIDsNew = srcMap->getLocalNumElements();
1548 size_t numRemoteIDsNew = this->getNumRemoteIDs();
1549 Array<LO> permuteToLIDsNew, permuteFromLIDsNew; // empty on purpose
1550
1551 // Grab some old data
1552 ArrayView<const LO> remoteLIDsOld = this->getRemoteLIDs();
1553 ArrayView<const LO> exportLIDsOld = this->getExportLIDs();
1554
1555 // Build up the new map (same part)
1557 for (size_t i = 0; i < numSameIDsNew; i++)
1558 GIDs[i] = srcGIDs[i];
1559
1560 // Build up the new map (remote part) and remotes list
1562 for (size_t i = 0; i < numRemoteIDsNew; i++) {
1565 }
1566
1567 // Build the new target map
1568 GO GO_INVALID = Teuchos::OrdinalTraits<GO>::invalid();
1570 rcp(new map_type(GO_INVALID, GIDs, tgtMap->getIndexBase(),
1571 tgtMap->getComm()));
1572
1573 // Exports are trivial (since the sourcemap doesn't change)
1574 Array<int> exportPIDsnew(this->getExportPIDs());
1575 Array<LO> exportLIDsnew(this->getExportLIDs());
1576
1577 // Copy the Distributor (due to how the Import constructor works)
1578 Distributor D(this->getDistributor());
1579
1580 // Build the importer using the "expert" constructor
1588 exportPIDsnew, D));
1589
1590 return unionImport;
1591}
1592
1593template <class LocalOrdinal, class GlobalOrdinal, class Node>
1594Teuchos::RCP<const Import<LocalOrdinal, GlobalOrdinal, Node>>
1596 createRemoteOnlyImport(const Teuchos::RCP<const map_type>& remoteTarget) const {
1597 using std::endl;
1598 using Teuchos::outArg;
1599 using Teuchos::rcp;
1600 using Teuchos::REDUCE_MIN;
1601 using Teuchos::reduceAll;
1602 using ::Tpetra::Details::Behavior;
1603 using ::Tpetra::Details::gathervPrint;
1604 using LO = LocalOrdinal;
1605 using GO = GlobalOrdinal;
1607
1608 const char funcPrefix[] = "Tpetra::createRemoteOnlyImport: ";
1609 int lclSuccess = 1;
1610 int gblSuccess = 1;
1611 const bool debug = Behavior::debug();
1612
1613 const size_t NumRemotes = this->getNumRemoteIDs();
1614 std::unique_ptr<std::string> procPrefix;
1615 Teuchos::RCP<const Teuchos::Comm<int>> comm;
1616 if (debug) {
1617 comm = remoteTarget.is_null() ? Teuchos::null : remoteTarget->getComm();
1618 std::ostringstream os;
1619 os << "Proc ";
1620 if (comm.is_null()) {
1621 os << "?";
1622 } else {
1623 os << comm->getRank();
1624 }
1625 os << ": ";
1626 procPrefix = std::unique_ptr<std::string>(new std::string(os.str()));
1627 }
1628
1629 if (debug) {
1630 std::ostringstream lclErr;
1631 if (remoteTarget.is_null()) {
1632 lclSuccess = -1;
1633 } else if (NumRemotes != remoteTarget->getLocalNumElements()) {
1634 lclSuccess = 0;
1635 lclErr << *procPrefix << "getNumRemoteIDs() = " << NumRemotes
1636 << " != remoteTarget->getLocalNumElements() = "
1637 << remoteTarget->getLocalNumElements() << "." << endl;
1638 }
1639
1640 if (comm.is_null()) {
1642 } else {
1644 }
1645 TEUCHOS_TEST_FOR_EXCEPTION(gblSuccess == -1, std::invalid_argument, funcPrefix << "Input target Map is null on at least one process.");
1646
1647 if (gblSuccess != 1) {
1648 if (comm.is_null()) {
1649 TEUCHOS_TEST_FOR_EXCEPTION(true, std::runtime_error, lclErr.str());
1650 } else {
1651 std::ostringstream gblErr;
1652 gblErr << funcPrefix << endl;
1653 gathervPrint(gblErr, lclErr.str(), *comm);
1654 TEUCHOS_TEST_FOR_EXCEPTION(true, std::runtime_error, gblErr.str());
1655 }
1656 }
1657 }
1658
1659 // Compute the new Remote LIDs
1660 Teuchos::ArrayView<const LO> oldRemoteLIDs = this->getRemoteLIDs();
1661 Teuchos::Array<LO> newRemoteLIDs(NumRemotes);
1662 const map_type& tgtMap = *(this->getTargetMap());
1663 size_t badCount = 0;
1664
1665 std::unique_ptr<std::vector<size_t>> badIndices;
1666 if (debug) {
1667 badIndices = std::unique_ptr<std::vector<size_t>>(new std::vector<size_t>);
1668 }
1669
1670 for (size_t i = 0; i < NumRemotes; ++i) {
1671 const LO oldLclInd = oldRemoteLIDs[i];
1672 if (oldLclInd == Teuchos::OrdinalTraits<LO>::invalid()) {
1673 ++badCount;
1674 if (debug) {
1675 badIndices->push_back(i);
1676 }
1677 continue;
1678 }
1679 const GO gblInd = tgtMap.getGlobalElement(oldLclInd);
1680 if (gblInd == Teuchos::OrdinalTraits<GO>::invalid()) {
1681 ++badCount;
1682 if (debug) {
1683 badIndices->push_back(i);
1684 }
1685 continue;
1686 }
1687 const LO newLclInd = remoteTarget->getLocalElement(gblInd);
1688 if (newLclInd == Teuchos::OrdinalTraits<LO>::invalid()) {
1689 ++badCount;
1690 if (debug) {
1691 badIndices->push_back(i);
1692 }
1693 continue;
1694 }
1696 // Now we make sure these guys are in sorted order (AztecOO-ML ordering)
1697 if (i > 0 && newRemoteLIDs[i] < newRemoteLIDs[i - 1]) {
1698 ++badCount;
1699 if (debug) {
1700 badIndices->push_back(i);
1701 }
1702 }
1703 }
1704
1705 if (badCount != 0) {
1706 lclSuccess = 0;
1707 }
1708
1709 if (debug) {
1710 if (comm.is_null()) {
1712 } else {
1714 }
1715 std::ostringstream lclErr;
1716 if (lclSuccess != 1) {
1717 lclErr << *procPrefix << "Count of bad indices: " << badCount
1718 << ", bad indices: [";
1719 // TODO (mfh 04 Sep 2019) Limit the maximum number of bad
1720 // indices to print.
1721 for (size_t k = 0; k < badCount; ++k) {
1722 const size_t badIndex = (*badIndices)[k];
1723 lclErr << "(" << badIndex << ","
1724 << oldRemoteLIDs[badIndex] << ")";
1725 if (k + size_t(1) < badCount) {
1726 lclErr << ", ";
1727 }
1728 }
1729 lclErr << "]" << endl;
1730 }
1731
1732 if (gblSuccess != 1) {
1733 std::ostringstream gblErr;
1734 gblErr << funcPrefix << "this->getRemoteLIDs() has \"bad\" "
1735 "indices on one or more processes. \"Bad\" means that the "
1736 "indices are invalid, they don't exist in the target Map, "
1737 "they don't exist in remoteTarget, or they are not in "
1738 "sorted order. In what follows, I will show the \"bad\" "
1739 "indices as (k, LID) pairs, where k is the zero-based "
1740 "index of the LID in this->getRemoteLIDs()."
1741 << endl;
1742 if (comm.is_null()) {
1743 gblErr << lclErr.str();
1744 } else {
1745 gathervPrint(gblErr, lclErr.str(), *comm);
1746 }
1747 TEUCHOS_TEST_FOR_EXCEPTION(true, std::runtime_error, gblErr.str());
1748 }
1749 } else { // not debug
1750 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);
1751 }
1752
1753 // Copy ExportPIDs and such
1754 // NOTE: Be careful: The "Expert" Import constructor we use does a "swap"
1755 // for most of the LID/PID lists and the Distributor, meaning it
1756 // ruins the existing object if we pass things in directly. Hence
1757 // we copy them first.
1758 Teuchos::Array<int> newExportPIDs(this->getExportPIDs());
1759 Teuchos::Array<LO> newExportLIDs(this->getExportLIDs());
1760 Teuchos::Array<LO> dummy;
1761 Distributor newDistor(this->getDistributor());
1762
1763 return rcp(new import_type(this->getSourceMap(), remoteTarget,
1764 static_cast<size_t>(0), dummy, dummy,
1767}
1768
1769} // namespace Tpetra
1770
1771#define TPETRA_IMPORT_CLASS_INSTANT(LO, GO, NODE) \
1772 template class Import<LO, GO, NODE>;
1773
1774// Explicit instantiation macro.
1775// Only invoke this when in the Tpetra namespace.
1776// Most users do not need to use this.
1777//
1778// LO: The local ordinal type.
1779// GO: The global ordinal type.
1780// NODE: The Kokkos Node type.
1781#define TPETRA_IMPORT_INSTANT(LO, GO, NODE) \
1782 TPETRA_IMPORT_CLASS_INSTANT(LO, GO, NODE)
1783
1784#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.
Declaration of Tpetra::Details::iallreduce.
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()).
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.