Tpetra parallel linear algebra Version of the Day
Loading...
Searching...
No Matches
Tpetra_Map_def.hpp
Go to the documentation of this file.
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
14
15#ifndef TPETRA_MAP_DEF_HPP
16#define TPETRA_MAP_DEF_HPP
17
18#include <memory>
19#include <sstream>
20#include <stdexcept>
21#include <typeinfo>
22
23#include "Teuchos_as.hpp"
24#include "Teuchos_TypeNameTraits.hpp"
25#include "Teuchos_CommHelpers.hpp"
26
27#include "Kokkos_Sort.hpp"
28
29#include "Tpetra_Directory.hpp" // must include for implicit instantiation to work
32#include "Tpetra_Details_FixedHashTable.hpp"
35#include "Tpetra_Core.hpp"
36#include "Tpetra_Map_decl.hpp"
37#include "Tpetra_Util.hpp"
38#include "Tpetra_Details_mpiIsInitialized.hpp"
39#include "Tpetra_Details_extractMpiCommFromTeuchos.hpp" // teuchosCommIsAnMpiComm
42
43namespace Tpetra {
44namespace Impl {
45
46inline void checkMapInputArray(const char ctorName[],
47 const void* indexList,
48 const size_t indexListSize,
49 const Teuchos::Comm<int>* const comm) {
51
52 const bool debug = Behavior::debug("Map");
53 if (debug) {
54 using std::endl;
55 using Teuchos::outArg;
56 using Teuchos::REDUCE_MIN;
57 using Teuchos::reduceAll;
58
59 const int myRank = comm == nullptr ? 0 : comm->getRank();
60 const bool verbose = Behavior::verbose("Map");
61 std::ostringstream lclErrStrm;
62 int lclSuccess = 1;
63
64 if (indexListSize != 0 && indexList == nullptr) {
65 lclSuccess = 0;
66 if (verbose) {
67 lclErrStrm << "Proc " << myRank << ": indexList is null, "
68 "but indexListSize="
69 << indexListSize << " != 0." << endl;
70 }
71 }
72 int gblSuccess = 0; // output argument
73 reduceAll(*comm, REDUCE_MIN, lclSuccess, outArg(gblSuccess));
74 if (gblSuccess != 1) {
75 std::ostringstream gblErrStrm;
76 gblErrStrm << "Tpetra::Map constructor " << ctorName << " detected a problem with the input array "
77 "(raw array, Teuchos::ArrayView, or Kokkos::View) "
78 "of global indices."
79 << endl;
80 if (verbose) {
81 using ::Tpetra::Details::gathervPrint;
82 gathervPrint(gblErrStrm, lclErrStrm.str(), *comm);
83 }
84 TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument, gblErrStrm.str());
85 }
86 }
87}
88
89template <class LocalOrdinal, class GlobalOrdinal, class ViewType>
90void computeConstantsOnDevice(const ViewType& entryList, GlobalOrdinal& minMyGID, GlobalOrdinal& maxMyGID, GlobalOrdinal& firstContiguousGID, GlobalOrdinal& lastContiguousGID_val, LocalOrdinal& lastContiguousGID_loc) {
91 using LO = LocalOrdinal;
92 using GO = GlobalOrdinal;
93 using exec_space = typename ViewType::device_type::execution_space;
94 using range_policy = Kokkos::RangePolicy<exec_space, Kokkos::IndexType<LO>>;
95 const LO numLocalElements = entryList.extent(0);
96
97 // We're going to use the minloc backwards because we need to have it sort on the "location" and have the "value" along for the
98 // ride, rather than the other way around
99 typedef typename Kokkos::MinLoc<LO, GO>::value_type minloc_type;
100 minloc_type myMinLoc;
101
102 // Find the initial sequence of parallel gids
103 // To find the lastContiguousGID_, we find the first guy where entryList[i] - entryList[0] != i-0. That's the first non-contiguous guy.
104 // We want the one *before* that guy.
105 Kokkos::parallel_reduce(
106 range_policy(0, numLocalElements), KOKKOS_LAMBDA(const LO& i, GO& l_myMin, GO& l_myMax, GO& l_firstCont, minloc_type& l_lastCont) {
107 GO entry_0 = entryList[0];
108 GO entry_i = entryList[i];
109
110 // Easy stuff
111 l_myMin = (l_myMin < entry_i) ? l_myMin : entry_i;
112 l_myMax = (l_myMax > entry_i) ? l_myMax : entry_i;
113 l_firstCont = entry_0;
114
115 if (entry_i - entry_0 != i && l_lastCont.val >= i) {
116 // We're non-contiguous, so the guy before us could be the last contiguous guy
117 l_lastCont.val = i - 1;
118 l_lastCont.loc = entryList[i - 1];
119 } else if (i == numLocalElements - 1 && i < l_lastCont.val) {
120 // If we're last, we always think we're the last contiguous guy, unless someone non-contiguous is already here
121 l_lastCont.val = i;
122 l_lastCont.loc = entry_i;
123 }
124 },
125 Kokkos::Min<GO>(minMyGID), Kokkos::Max<GO>(maxMyGID), Kokkos::Min<GO>(firstContiguousGID), Kokkos::MinLoc<LO, GO>(myMinLoc));
126
127 // This switch is intentional, since we're using MinLoc backwards
128 lastContiguousGID_val = myMinLoc.loc;
129 lastContiguousGID_loc = myMinLoc.val;
130}
131
132} // namespace Impl
133
134template <class LocalOrdinal, class GlobalOrdinal, class Node>
136 Map()
137 : comm_(new Teuchos::SerialComm<int>())
138 , indexBase_(0)
139 , numGlobalElements_(0)
140 , numLocalElements_(0)
145 , firstContiguousGID_(Tpetra::Details::OrdinalTraits<GlobalOrdinal>::invalid())
146 , lastContiguousGID_(Tpetra::Details::OrdinalTraits<GlobalOrdinal>::invalid())
147 , uniform_(false)
148 , // trivially
149 contiguous_(false)
150 , distributed_(false)
151 , haveGlobalConstants_(true)
152 , // no communicator yet
153 directory_(new Directory<LocalOrdinal, GlobalOrdinal, Node>()) {
156}
157
158template <class LocalOrdinal, class GlobalOrdinal, class Node>
162 const Teuchos::RCP<const Teuchos::Comm<int>>& comm,
163 const LocalGlobal lOrG)
164 : comm_(comm)
165 , uniform_(true)
166 , directory_(new Directory<LocalOrdinal, GlobalOrdinal, Node>()) {
167 using std::endl;
168 using Teuchos::as;
169 using Teuchos::broadcast;
170 using Teuchos::outArg;
171 using Teuchos::REDUCE_MAX;
172 using Teuchos::REDUCE_MIN;
173 using Teuchos::reduceAll;
174 using Teuchos::typeName;
175 using GO = global_ordinal_type;
176 using GST = global_size_t;
177 const GST GSTI = Tpetra::Details::OrdinalTraits<GST>::invalid();
178 const char funcName[] = "Map(gblNumInds,indexBase,comm,LG)";
179 const char exPfx[] =
180 "Tpetra::Map::Map(gblNumInds,indexBase,comm,LG): ";
181
182 const bool debug = Details::Behavior::debug("Map");
183 const bool verbose = Details::Behavior::verbose("Map");
184 std::unique_ptr<std::string> prefix;
185 if (verbose) {
187 comm_.getRawPtr(), "Map", funcName);
188 std::ostringstream os;
189 os << *prefix << "Start" << endl;
190 std::cerr << os.str();
191 }
194
195 // In debug mode only, check whether numGlobalElements and
196 // indexBase are the same over all processes in the communicator.
197 if (debug) {
208 std::invalid_argument, exPfx << "All processes must "
209 "provide the same number of global elements. Process 0 set "
210 "numGlobalElements="
211 << proc0NumGlobalElements << ". The "
212 "calling process "
213 << comm->getRank() << " set "
214 "numGlobalElements="
215 << numGlobalElements << ". The min "
216 "and max values over all processes are "
217 << minNumGlobalElements << " resp. " << maxNumGlobalElements << ".");
218
226 std::invalid_argument, exPfx << "All processes must "
227 "provide the same indexBase argument. Process 0 set "
228 "indexBase="
229 << proc0IndexBase << ". The calling process " << comm->getRank() << " set indexBase=" << indexBase << ". The min and max values over all processes are " << minIndexBase << " resp. " << maxIndexBase << ".");
230 }
231
232 // Distribute the elements across the processes in the given
233 // communicator so that global IDs (GIDs) are
234 //
235 // - Nonoverlapping (only one process owns each GID)
236 // - Contiguous (the sequence of GIDs is nondecreasing, and no two
237 // adjacent GIDs differ by more than one)
238 // - As evenly distributed as possible (the numbers of GIDs on two
239 // different processes do not differ by more than one)
240
241 // All processes have the same numGlobalElements, but we still
242 // need to check that it is valid. numGlobalElements must be
243 // positive and not the "invalid" value (GSTI).
244 //
245 // This comparison looks funny, but it avoids compiler warnings
246 // for comparing unsigned integers (numGlobalElements_in is a
247 // GST, which is unsigned) while still working if we
248 // later decide to make GST signed.
251 std::invalid_argument, exPfx << "numGlobalElements (= " << numGlobalElements << ") must be nonnegative.");
252
253 TEUCHOS_TEST_FOR_EXCEPTION(numGlobalElements == GSTI, std::invalid_argument, exPfx << "You provided numGlobalElements = Teuchos::OrdinalTraits<"
254 "Tpetra::global_size_t>::invalid(). This version of the "
255 "constructor requires a valid value of numGlobalElements. "
256 "You probably mistook this constructor for the \"contiguous "
257 "nonuniform\" constructor, which can compute the global "
258 "number of elements for you if you set numGlobalElements to "
259 "Teuchos::OrdinalTraits<Tpetra::global_size_t>::invalid().");
260
261 size_t numLocalElements = 0; // will set below
262 if (lOrG == GloballyDistributed) {
263 // Compute numLocalElements:
264 //
265 // If numGlobalElements == numProcs * B + remainder,
266 // then Proc r gets B+1 elements if r < remainder,
267 // and B elements if r >= remainder.
268 //
269 // This strategy is valid for any value of numGlobalElements and
270 // numProcs, including the following border cases:
271 // - numProcs == 1
272 // - numLocalElements < numProcs
273 //
274 // In the former case, remainder == 0 && numGlobalElements ==
275 // numLocalElements. In the latter case, remainder ==
276 // numGlobalElements && numLocalElements is either 0 or 1.
277 const GST numProcs = static_cast<GST>(comm_->getSize());
278 const GST myRank = static_cast<GST>(comm_->getRank());
281
282 GO startIndex;
283 if (myRank < remainder) {
284 numLocalElements = static_cast<size_t>(1) + static_cast<size_t>(quotient);
285 // myRank was originally an int, so it should never overflow
286 // reasonable GO types.
288 } else {
292 }
293
294 minMyGID_ = indexBase + startIndex;
295 maxMyGID_ = indexBase + startIndex + numLocalElements - 1;
296 minAllGID_ = indexBase;
297 maxAllGID_ = indexBase + numGlobalElements - 1;
298 distributed_ = (numProcs > 1);
299 } else { // lOrG == LocallyReplicated
301 minMyGID_ = indexBase;
302 maxMyGID_ = indexBase + numGlobalElements - 1;
303 distributed_ = false;
304 }
305
306 minAllGID_ = indexBase;
307 maxAllGID_ = indexBase + numGlobalElements - 1;
308 indexBase_ = indexBase;
309 numGlobalElements_ = numGlobalElements;
310 numLocalElements_ = numLocalElements;
311 firstContiguousGID_ = minMyGID_;
312 lastContiguousGID_ = maxMyGID_;
313 contiguous_ = true;
314 haveGlobalConstants_ = true;
315
316 // Create the Directory on demand in getRemoteIndexList().
317 // setupDirectory ();
318
319 if (verbose) {
320 std::ostringstream os;
321 os << *prefix << "Done" << endl;
322 std::cerr << os.str();
323 }
324}
325
326template <class LocalOrdinal, class GlobalOrdinal, class Node>
329 const size_t numLocalElements,
331 const Teuchos::RCP<const Teuchos::Comm<int>>& comm)
332 : comm_(comm)
333 , uniform_(false)
334 , directory_(new Directory<LocalOrdinal, GlobalOrdinal, Node>()) {
335 using std::endl;
336 using Teuchos::as;
337 using Teuchos::broadcast;
338 using Teuchos::outArg;
339 using Teuchos::REDUCE_MAX;
340 using Teuchos::REDUCE_MIN;
341 using Teuchos::REDUCE_SUM;
342 using Teuchos::reduceAll;
343 using Teuchos::scan;
344 using GO = global_ordinal_type;
345 using GST = global_size_t;
346 const GST GSTI = Tpetra::Details::OrdinalTraits<GST>::invalid();
347 const char funcName[] =
348 "Map(gblNumInds,lclNumInds,indexBase,comm)";
349 const char exPfx[] =
350 "Tpetra::Map::Map(gblNumInds,lclNumInds,indexBase,comm): ";
351 const char suffix[] =
352 ". Please report this bug to the Tpetra developers.";
353
354 const bool debug = Details::Behavior::debug("Map");
355 const bool verbose = Details::Behavior::verbose("Map");
356 std::unique_ptr<std::string> prefix;
357 if (verbose) {
359 comm_.getRawPtr(), "Map", funcName);
360 std::ostringstream os;
361 os << *prefix << "Start" << endl;
362 std::cerr << os.str();
363 }
366
367 // Global sum of numLocalElements over all processes.
368 // Keep this for later debug checks.
370 if (debug) {
371 debugGlobalSum = initialNonuniformDebugCheck(exPfx,
373 }
374
375 // Distribute the elements across the nodes so that they are
376 // - non-overlapping
377 // - contiguous
378
379 // This differs from the first Map constructor (that only takes a
380 // global number of elements) in that the user has specified the
381 // number of local elements, so that the elements are not
382 // (necessarily) evenly distributed over the processes.
383
384 // Compute my local offset. This is an inclusive scan, so to get
385 // the final offset, we subtract off the input.
386 GO scanResult = 0;
389
390 if (numGlobalElements != GSTI) {
391 numGlobalElements_ = numGlobalElements; // Use the user's value.
392 } else {
393 // Inclusive scan means that the last process has the final sum.
394 // Rather than doing a reduceAll to get the sum of
395 // numLocalElements, we can just have the last process broadcast
396 // its result. That saves us a round of log(numProcs) messages.
397 const int numProcs = comm->getSize();
399 if (numProcs > 1) {
400 broadcast(*comm, numProcs - 1, outArg(globalSum));
401 }
402 numGlobalElements_ = globalSum;
403
404 if (debug) {
405 // No need for an all-reduce here; both come from collectives.
406 TEUCHOS_TEST_FOR_EXCEPTION(globalSum != debugGlobalSum, std::logic_error, exPfx << "globalSum = " << globalSum << " != debugGlobalSum = " << debugGlobalSum << suffix);
407 }
408 }
409 numLocalElements_ = numLocalElements;
410 indexBase_ = indexBase;
411 minAllGID_ = (numGlobalElements_ == 0) ? std::numeric_limits<GO>::max() : indexBase;
412 maxAllGID_ = (numGlobalElements_ == 0) ? std::numeric_limits<GO>::lowest() : indexBase + GO(numGlobalElements_) - GO(1);
413 minMyGID_ = (numLocalElements_ == 0) ? std::numeric_limits<GO>::max() : indexBase + GO(myOffset);
414 maxMyGID_ = (numLocalElements_ == 0) ? std::numeric_limits<GO>::lowest() : indexBase + myOffset + GO(numLocalElements) - GO(1);
415 firstContiguousGID_ = minMyGID_;
416 lastContiguousGID_ = maxMyGID_;
417 contiguous_ = true;
418 distributed_ = (comm->getSize() > 1);
419 haveGlobalConstants_ = true;
420
421 // Create the Directory on demand in getRemoteIndexList().
422 // setupDirectory ();
423
424 if (verbose) {
425 std::ostringstream os;
426 os << *prefix << "Done" << endl;
427 std::cerr << os.str();
428 }
429}
430
431template <class LocalOrdinal, class GlobalOrdinal, class Node>
433Map<LocalOrdinal, GlobalOrdinal, Node>::
434 initialNonuniformDebugCheck(
435 const char errorMessagePrefix[],
436 const global_size_t numGlobalElements,
437 const size_t numLocalElements,
438 const global_ordinal_type indexBase,
439 const Teuchos::RCP<const Teuchos::Comm<int>>& comm) const {
440 const bool debug = Details::Behavior::debug("Map");
441 if (!debug) {
442 return global_size_t(0);
443 }
444
445 using Teuchos::broadcast;
446 using Teuchos::outArg;
447 using Teuchos::ptr;
448 using Teuchos::REDUCE_MAX;
449 using Teuchos::REDUCE_MIN;
450 using Teuchos::REDUCE_SUM;
451 using Teuchos::reduceAll;
452 using GO = global_ordinal_type;
453 using GST = global_size_t;
454 const GST GSTI = Tpetra::Details::OrdinalTraits<GST>::invalid();
455
456 // The user has specified the distribution of indices over the
457 // processes. The distribution is not necessarily contiguous or
458 // equally shared over the processes.
459 //
460 // We assume that the number of local elements can be stored in a
461 // size_t. The instance member numLocalElements_ is a size_t, so
462 // this variable and that should have the same type.
463
464 GST debugGlobalSum = 0; // Will be global sum of numLocalElements
467 // In debug mode only, check whether numGlobalElements and
468 // indexBase are the same over all processes in the communicator.
469 {
480 std::invalid_argument, errorMessagePrefix << "All processes "
481 "must provide the same number of global elements, even if "
482 "that argument is "
483 "Teuchos::OrdinalTraits<Tpetra::global_size_t>::invalid() "
484 "(which signals that the Map should compute the global "
485 "number of elements). Process 0 set numGlobalElements"
486 "="
487 << proc0NumGlobalElements << ". The calling process " << comm->getRank() << " set numGlobalElements=" << numGlobalElements << ". The min and max values over all "
488 "processes are "
489 << minNumGlobalElements << " resp. " << maxNumGlobalElements << ".");
490
498 std::invalid_argument, errorMessagePrefix << "All processes must provide the same indexBase argument. "
499 "Process 0 set indexBase = "
500 << proc0IndexBase << ". The "
501 "calling process "
502 << comm->getRank() << " set indexBase=" << indexBase << ". The min and max values over all "
503 "processes are "
504 << minIndexBase << " resp. " << maxIndexBase << ".");
505
506 // Make sure that the sum of numLocalElements over all processes
507 // equals numGlobalElements.
510 std::invalid_argument,
511 errorMessagePrefix << "The sum of each process' number of "
512 "indices over all processes, "
513 << debugGlobalSum << ", != "
514 << "numGlobalElements=" << numGlobalElements << ". If you "
515 "would like this constructor to compute numGlobalElements "
516 "for you, you may set numGlobalElements="
517 "Teuchos::OrdinalTraits<Tpetra::global_size_t>::invalid() "
518 "on input. Please note that this is NOT necessarily -1.");
519 }
520 return debugGlobalSum;
521}
522
523template <class LocalOrdinal, class GlobalOrdinal, class Node>
524void Map<LocalOrdinal, GlobalOrdinal, Node>::
525 initWithNonownedHostIndexList(
526 const char errorMessagePrefix[],
527 const global_size_t numGlobalElements,
528 const Kokkos::View<const global_ordinal_type*,
529 Kokkos::LayoutLeft,
530 Kokkos::HostSpace,
531 Kokkos::MemoryUnmanaged>& entryList_host,
532 const global_ordinal_type indexBase,
533 const Teuchos::RCP<const Teuchos::Comm<int>>& comm,
534 const Teuchos::RCP<Teuchos::ParameterList>& params) {
535 Tpetra::Details::ProfilingRegion pr("Map::initWithNonownedHostIndexList()");
536
537 using Kokkos::LayoutLeft;
538 using Kokkos::subview;
539 using Kokkos::View;
540 using Kokkos::view_alloc;
541 using Kokkos::WithoutInitializing;
542 using Teuchos::as;
543 using Teuchos::broadcast;
544 using Teuchos::outArg;
545 using Teuchos::ptr;
546 using Teuchos::REDUCE_MAX;
547 using Teuchos::REDUCE_MIN;
548 using Teuchos::REDUCE_SUM;
549 using Teuchos::reduceAll;
550 using LO = local_ordinal_type;
551 using GO = global_ordinal_type;
553 const GST GSTI = Tpetra::Details::OrdinalTraits<GST>::invalid();
554 // Make sure that Kokkos has been initialized (Github Issue #513).
555 TEUCHOS_TEST_FOR_EXCEPTION(!Kokkos::is_initialized(), std::runtime_error,
556 errorMessagePrefix << "The Kokkos execution space "
557 << Teuchos::TypeNameTraits<execution_space>::name()
558 << " has not been initialized. "
559 "Please initialize it before creating a Map.")
560
561 // The user has specified the distribution of indices over the
562 // processes, via the input array of global indices on each
563 // process. The distribution is not necessarily contiguous or
564 // equally shared over the processes.
565
566 // The length of the input array on this process is the number of
567 // local indices to associate with this process, even though the
568 // input array contains global indices. We assume that the number
569 // of local indices on a process can be stored in a size_t;
570 // numLocalElements_ is a size_t, so this variable and that should
571 // have the same type.
573
574 initialNonuniformDebugCheck(errorMessagePrefix, numGlobalElements,
576
577 // NOTE (mfh 20 Feb 2013, 10 Oct 2016) In some sense, this global
578 // reduction is redundant, since the directory Map will have to do
579 // the same thing. Thus, we could do the scan and broadcast for
580 // the directory Map here, and give the computed offsets to the
581 // directory Map's constructor. However, a reduction costs less
582 // than a scan and broadcast, so this still saves time if users of
583 // this Map don't ever need the Directory (i.e., if they never
584 // call getRemoteIndexList on this Map).
585 std::shared_ptr<Details::CommRequest> req;
588 numGlobalElements_ = numGlobalElements; // Use the user's value.
589 } else { // The user wants us to compute the sum.
591 req = Details::iallreduce(numLocalElementsGST,
592 numGlobalElements_, REDUCE_SUM, *comm);
593 }
594
595 // mfh 20 Feb 2013: We've never quite done the right thing for
596 // duplicate GIDs here. Duplicate GIDs have always been counted
597 // distinctly in numLocalElements_, and thus should get a
598 // different LID. However, we've always used std::map or a hash
599 // table for the GID -> LID lookup table, so distinct GIDs always
600 // map to the same LID. Furthermore, the order of the input GID
601 // list matters, so it's not desirable to sort for determining
602 // uniqueness.
603 //
604 // I've chosen for now to write this code as if the input GID list
605 // contains no duplicates. If this is not desired, we could use
606 // the lookup table itself to determine uniqueness: If we haven't
607 // seen the GID before, it gets a new LID and it's added to the
608 // LID -> GID and GID -> LID tables. If we have seen the GID
609 // before, it doesn't get added to either table. I would
610 // implement this, but it would cost more to do the double lookups
611 // in the table (one to check, and one to insert).
612 //
613 // More importantly, since we build the GID -> LID table in (a
614 // thread-) parallel (way), the order in which duplicate GIDs may
615 // get inserted is not defined. This would make the assignment of
616 // LID to GID nondeterministic.
617
618 numLocalElements_ = numLocalElements;
619 indexBase_ = indexBase;
620
621 minMyGID_ = indexBase_;
622 maxMyGID_ = indexBase_;
623
624 // NOTE (mfh 27 May 2015): While finding the initial contiguous
625 // GID range requires looking at all the GIDs in the range,
626 // dismissing an interval of GIDs only requires looking at the
627 // first and last GIDs. Thus, we could do binary search backwards
628 // from the end in order to catch the common case of a contiguous
629 // interval followed by noncontiguous entries. On the other hand,
630 // we could just expose this case explicitly as yet another Map
631 // constructor, and avoid the trouble of detecting it.
632 if (numLocalElements_ > 0) {
633 Tpetra::Details::ProfilingRegion prLcl("Map::initWithNonownedHostIndexList::local");
634 // Find contiguous GID range, with the restriction that the
635 // beginning of the range starts with the first entry. While
636 // doing so, fill in the LID -> GID table.
637 typename decltype(lgMap_)::non_const_type lgMap(view_alloc("lgMap", WithoutInitializing), numLocalElements_);
638 auto lgMap_host =
639 Kokkos::create_mirror_view(Kokkos::HostSpace(), lgMap);
640
641 // The input array entryList_host is already on host, so we
642 // don't need to take a host view of it.
643 // auto entryList_host =
644 // Kokkos::create_mirror_view (Kokkos::HostSpace (), entryList);
645 // Kokkos::deep_copy (entryList_host, entryList);
646
647 firstContiguousGID_ = entryList_host[0];
648 lastContiguousGID_ = firstContiguousGID_ + 1;
649
650 // FIXME (mfh 23 Sep 2015) We need to copy the input GIDs
651 // anyway, so we have to look at them all. The logical way to
652 // find the first noncontiguous entry would thus be to "reduce,"
653 // where the local reduction result is whether entryList[i] + 1
654 // == entryList[i+1].
655
656 lgMap_host[0] = firstContiguousGID_;
657 size_t i = 1;
658 for (; i < numLocalElements_; ++i) {
659 const GO curGid = entryList_host[i];
660 const LO curLid = as<LO>(i);
661
662 if (lastContiguousGID_ != curGid) break;
663
664 // Add the entry to the LID->GID table only after we know that
665 // the current GID is in the initial contiguous sequence, so
666 // that we don't repeat adding it in the first iteration of
667 // the loop below over the remaining noncontiguous GIDs.
669 ++lastContiguousGID_;
670 }
671 --lastContiguousGID_;
672 // NOTE: i is the first non-contiguous index.
673
674 // [firstContiguousGID_, lastContigousGID_] is the initial
675 // sequence of contiguous GIDs. We can start the min and max
676 // GID using this range.
677 minMyGID_ = firstContiguousGID_;
678 maxMyGID_ = lastContiguousGID_;
679
680 // Compute the GID -> LID lookup table, _not_ including the
681 // initial sequence of contiguous GIDs.
683 {
684 const std::pair<size_t, size_t> ncRange(i, entryList_host.extent(0));
686 TEUCHOS_TEST_FOR_EXCEPTION(static_cast<size_t>(nonContigGids_host.extent(0)) !=
687 static_cast<size_t>(entryList_host.extent(0) - i),
688 std::logic_error,
689 "Tpetra::Map noncontiguous constructor: "
690 "nonContigGids_host.extent(0) = "
691 << nonContigGids_host.extent(0)
692 << " != entryList_host.extent(0) - i = "
693 << (entryList_host.extent(0) - i) << " = "
694 << entryList_host.extent(0) << " - " << i
695 << ". Please report this bug to the Tpetra developers.");
696
697 // FixedHashTable's constructor expects an owned device View,
698 // so we must deep-copy the subview of the input indices.
701 nonContigGids_host.size());
702
703 // DEEP_COPY REVIEW - HOST-TO-DEVICE
704 Kokkos::deep_copy(execution_space(), nonContigGids, nonContigGids_host);
705 Kokkos::fence("Map::initWithNonownedHostIndexList"); // for UVM issues below - which will be refatored soon so FixedHashTable can build as pure CudaSpace - then I think remove this fence
706
709 // Make host version - when memory spaces match these just do trivial assignment
710 glMapHost_ = global_to_local_table_host_type(glMap_);
711 }
712
713 // FIXME (mfh 10 Oct 2016) When we construct the global-to-local
714 // table above, we have to look at all the (noncontiguous) input
715 // indices anyway. Thus, why not have the constructor compute
716 // and return the min and max?
717
718 for (; i < numLocalElements_; ++i) {
719 const GO curGid = entryList_host[i];
720 const LO curLid = static_cast<LO>(i);
721 lgMap_host[curLid] = curGid; // LID -> GID table
722
723 // While iterating through entryList, we compute its
724 // (process-local) min and max elements.
725 if (curGid < minMyGID_) {
726 minMyGID_ = curGid;
727 }
728 if (curGid > maxMyGID_) {
729 maxMyGID_ = curGid;
730 }
731 }
732
733 // We filled lgMap on host above; now sync back to device.
734 // DEEP_COPY REVIEW - HOST-TO-DEVICE
735 Kokkos::deep_copy(execution_space(), lgMap, lgMap_host);
736
737 // "Commit" the local-to-global lookup table we filled in above.
738 lgMap_ = lgMap;
739 // We've already created this, so use it.
740 lgMapHost_ = lgMap_host;
741
742 } else {
743 minMyGID_ = std::numeric_limits<GlobalOrdinal>::max();
744 maxMyGID_ = std::numeric_limits<GlobalOrdinal>::lowest();
745 // This insures tests for GIDs in the range
746 // [firstContiguousGID_, lastContiguousGID_] fail for processes
747 // with no local elements.
748 firstContiguousGID_ = indexBase_ + 1;
749 lastContiguousGID_ = indexBase_;
750 // glMap_ was default constructed, so it's already empty.
751 }
752
753 contiguous_ = false; // "Contiguous" is conservative.
754
755 if (req) req->wait();
756
757 const bool callComputeGlobalConstants = (params.get() == nullptr) ||
758 params->get("compute global constants", true) ||
759 (comm->getSize() == 1);
760
761 if (callComputeGlobalConstants)
762 computeGlobalConstants();
763 else {
764 distributed_ = params->get("distributed", true);
765 }
766
767 // Create the Directory on demand in getRemoteIndexList().
768 // setupDirectory ();
769}
770
771template <class LocalOrdinal, class GlobalOrdinal, class Node>
774 const GlobalOrdinal indexList[],
777 const Teuchos::RCP<const Teuchos::Comm<int>>& comm,
778 const Teuchos::RCP<Teuchos::ParameterList>& params)
779 : comm_(comm)
780 , uniform_(false)
781 , directory_(new Directory<LocalOrdinal, GlobalOrdinal, Node>()) {
782 using std::endl;
783 const char funcName[] =
784 "Map(gblNumInds,indexList,indexListSize,indexBase,comm)";
785
786 const bool verbose = Details::Behavior::verbose("Map");
787 std::unique_ptr<std::string> prefix;
788 if (verbose) {
790 comm_.getRawPtr(), "Map", funcName);
791 std::ostringstream os;
792 os << *prefix << "Start" << endl;
793 std::cerr << os.str();
794 }
798 Impl::checkMapInputArray("(GST, const GO[], LO, GO, comm)",
799 indexList, static_cast<size_t>(indexListSize),
800 comm.getRawPtr());
801 // Not quite sure if I trust all code to behave correctly if the
802 // pointer is nonnull but the array length is nonzero, so I'll
803 // make sure the raw pointer is null if the length is zero.
804 const GlobalOrdinal* const indsRaw = indexListSize == 0 ? NULL : indexList;
805 Kokkos::View<const GlobalOrdinal*,
806 Kokkos::LayoutLeft,
807 Kokkos::HostSpace,
808 Kokkos::MemoryUnmanaged>
810 initWithNonownedHostIndexList(funcName, numGlobalElements, inds,
811 indexBase, comm, params);
812 if (verbose) {
813 std::ostringstream os;
814 os << *prefix << "Done" << endl;
815 std::cerr << os.str();
817}
818
819template <class LocalOrdinal, class GlobalOrdinal, class Node>
822 const Teuchos::ArrayView<const GlobalOrdinal>& entryList,
824 const Teuchos::RCP<const Teuchos::Comm<int>>& comm,
825 const Teuchos::RCP<Teuchos::ParameterList>& params)
826 : comm_(comm)
827 , uniform_(false)
828 , directory_(new Directory<LocalOrdinal, GlobalOrdinal, Node>()) {
829 using std::endl;
830 const char* funcName = "Map(gblNumInds,entryList(Teuchos::ArrayView),indexBase,comm)";
831
832 const bool verbose = Details::Behavior::verbose("Map");
833 std::unique_ptr<std::string> prefix;
834 if (verbose) {
835 prefix = Details::createPrefix(
836 comm_.getRawPtr(), "Map", funcName);
837 std::ostringstream os;
838 os << *prefix << "Start" << endl;
839 std::cerr << os.str();
840 }
844 const size_t numLclInds = static_cast<size_t>(entryList.size());
845 Impl::checkMapInputArray("(GST, ArrayView, GO, comm)",
846 entryList.getRawPtr(), numLclInds,
847 comm.getRawPtr());
848 // Not quite sure if I trust both ArrayView and View to behave
849 // correctly if the pointer is nonnull but the array length is
850 // nonzero, so I'll make sure it's null if the length is zero.
851 const GlobalOrdinal* const indsRaw =
852 numLclInds == 0 ? NULL : entryList.getRawPtr();
853 Kokkos::View<const GlobalOrdinal*,
854 Kokkos::LayoutLeft,
855 Kokkos::HostSpace,
856 Kokkos::MemoryUnmanaged>
858 initWithNonownedHostIndexList(funcName, numGlobalElements, inds,
860 if (verbose) {
861 std::ostringstream os;
862 os << *prefix << "Done" << endl;
863 std::cerr << os.str();
864 }
865}
866
867template <class LocalOrdinal, class GlobalOrdinal, class Node>
870 const Kokkos::View<const GlobalOrdinal*, device_type>& entryList,
872 const Teuchos::RCP<const Teuchos::Comm<int>>& comm,
873 const Teuchos::RCP<Teuchos::ParameterList>& params)
874 : comm_(comm)
875 , uniform_(false)
876 , directory_(new Directory<LocalOrdinal, GlobalOrdinal, Node>()) {
877 using Kokkos::LayoutLeft;
878 using Kokkos::subview;
879 using Kokkos::View;
880 using Kokkos::view_alloc;
881 using Kokkos::WithoutInitializing;
882 using std::endl;
883 using Teuchos::arcp;
884 using Teuchos::ArrayView;
885 using Teuchos::as;
886 using Teuchos::broadcast;
887 using Teuchos::outArg;
888 using Teuchos::ptr;
889 using Teuchos::REDUCE_MAX;
890 using Teuchos::REDUCE_MIN;
891 using Teuchos::REDUCE_SUM;
892 using Teuchos::reduceAll;
893 using Teuchos::typeName;
894 using LO = local_ordinal_type;
895 using GST = global_size_t;
896 const GST GSTI = Tpetra::Details::OrdinalTraits<GST>::invalid();
897 const char funcName[] =
898 "Map(gblNumInds,entryList(Kokkos::View),indexBase,comm)";
899
900 const bool verbose = Details::Behavior::verbose("Map");
901 std::unique_ptr<std::string> prefix;
902 if (verbose) {
904 comm_.getRawPtr(), "Map", funcName);
905 std::ostringstream os;
906 os << *prefix << "Start" << endl;
907 std::cerr << os.str();
908 }
912 Impl::checkMapInputArray("(GST, Kokkos::View, GO, comm)",
913 entryList.data(),
914 static_cast<size_t>(entryList.extent(0)),
915 comm.getRawPtr());
916
917 // The user has specified the distribution of indices over the
918 // processes, via the input array of global indices on each
919 // process. The distribution is not necessarily contiguous or
920 // equally shared over the processes.
921
922 // The length of the input array on this process is the number of
923 // local indices to associate with this process, even though the
924 // input array contains global indices. We assume that the number
925 // of local indices on a process can be stored in a size_t;
926 // numLocalElements_ is a size_t, so this variable and that should
927 // have the same type.
928 const size_t numLocalElements(entryList.size());
929
930 initialNonuniformDebugCheck(funcName, numGlobalElements,
932
933 // NOTE (mfh 20 Feb 2013, 10 Oct 2016) In some sense, this global
934 // reduction is redundant, since the directory Map will have to do
935 // the same thing. Thus, we could do the scan and broadcast for
936 // the directory Map here, and give the computed offsets to the
937 // directory Map's constructor. However, a reduction costs less
938 // than a scan and broadcast, so this still saves time if users of
939 // this Map don't ever need the Directory (i.e., if they never
940 // call getRemoteIndexList on this Map).
941 std::shared_ptr<Details::CommRequest> req;
943 if (numGlobalElements != GSTI) {
944 numGlobalElements_ = numGlobalElements; // Use the user's value.
945 } else { // The user wants us to compute the sum.
947 req = Details::iallreduce(numLocalElementsGST,
948 numGlobalElements_, REDUCE_SUM, *comm);
949 }
950
951 // mfh 20 Feb 2013: We've never quite done the right thing for
952 // duplicate GIDs here. Duplicate GIDs have always been counted
953 // distinctly in numLocalElements_, and thus should get a
954 // different LID. However, we've always used std::map or a hash
955 // table for the GID -> LID lookup table, so distinct GIDs always
956 // map to the same LID. Furthermore, the order of the input GID
957 // list matters, so it's not desirable to sort for determining
958 // uniqueness.
959 //
960 // I've chosen for now to write this code as if the input GID list
961 // contains no duplicates. If this is not desired, we could use
962 // the lookup table itself to determine uniqueness: If we haven't
963 // seen the GID before, it gets a new LID and it's added to the
964 // LID -> GID and GID -> LID tables. If we have seen the GID
965 // before, it doesn't get added to either table. I would
966 // implement this, but it would cost more to do the double lookups
967 // in the table (one to check, and one to insert).
968 //
969 // More importantly, since we build the GID -> LID table in (a
970 // thread-) parallel (way), the order in which duplicate GIDs may
971 // get inserted is not defined. This would make the assignment of
972 // LID to GID nondeterministic.
973
974 numLocalElements_ = numLocalElements;
975 indexBase_ = indexBase;
976
977 minMyGID_ = indexBase_;
978 maxMyGID_ = indexBase_;
979
980 // NOTE (mfh 27 May 2015): While finding the initial contiguous
981 // GID range requires looking at all the GIDs in the range,
982 // dismissing an interval of GIDs only requires looking at the
983 // first and last GIDs. Thus, we could do binary search backwards
984 // from the end in order to catch the common case of a contiguous
985 // interval followed by noncontiguous entries. On the other hand,
986 // we could just expose this case explicitly as yet another Map
987 // constructor, and avoid the trouble of detecting it.
988 if (numLocalElements_ > 0) {
989 // Find contiguous GID range, with the restriction that the
990 // beginning of the range starts with the first entry. While
991 // doing so, fill in the LID -> GID table.
992 typename decltype(lgMap_)::non_const_type lgMap(view_alloc("lgMap2", WithoutInitializing), numLocalElements_);
993
994 // Because you can't use lambdas in constructors on CUDA. Or using private/protected data.
995 // DEEP_COPY REVIEW - DEVICE-TO-DEVICE
996 Kokkos::deep_copy(typename device_type::execution_space(), lgMap, entryList);
998 Impl::computeConstantsOnDevice(entryList, minMyGID_, maxMyGID_, firstContiguousGID_, lastContiguousGID_, lastContiguousGID_loc);
1000 auto nonContigGids = Kokkos::subview(entryList, std::pair<size_t, size_t>(firstNonContiguous_loc, entryList.extent(0)));
1001
1002 // NOTE: We do not fill the glMapHost_ and lgMapHost_ views here. They will be filled lazily later
1005
1006 // "Commit" the local-to-global lookup table we filled in above.
1007 lgMap_ = lgMap;
1008
1009 } else {
1010 minMyGID_ = std::numeric_limits<GlobalOrdinal>::max();
1011 maxMyGID_ = std::numeric_limits<GlobalOrdinal>::lowest();
1012 // This insures tests for GIDs in the range
1013 // [firstContiguousGID_, lastContiguousGID_] fail for processes
1014 // with no local elements.
1015 firstContiguousGID_ = indexBase_ + 1;
1016 lastContiguousGID_ = indexBase_;
1017 // glMap_ was default constructed, so it's already empty.
1018 }
1019
1020 if (req) req->wait();
1021
1022 const bool callComputeGlobalConstants = (params.get() == nullptr) ||
1023 params->get("compute global constants", true) ||
1024 (comm->getSize() == 1);
1025
1026 if (callComputeGlobalConstants)
1028 else {
1029 distributed_ = params->get("distributed", true);
1030 }
1031
1032 contiguous_ = false; // "Contiguous" is conservative.
1033
1034 // Create the Directory on demand in getRemoteIndexList().
1035 // setupDirectory ();
1036
1037 if (verbose) {
1038 std::ostringstream os;
1039 os << *prefix << "Done" << endl;
1040 std::cerr << os.str();
1041 }
1042}
1043
1044template <class LocalOrdinal, class GlobalOrdinal, class Node>
1046 using GO = global_ordinal_type;
1047 using GST = global_size_t;
1048
1049 if (haveGlobalConstants_)
1050 return;
1051
1052 if (comm_->getSize() == 1) {
1053 minAllGID_ = minMyGID_;
1054 maxAllGID_ = maxMyGID_;
1055 distributed_ = false;
1056 haveGlobalConstants_ = true;
1057 return;
1058 }
1059
1060 Tpetra::Details::ProfilingRegion pr("Tpetra::Map::computeGlobalConstants");
1061
1062 // Compute the min and max of all processes' GIDs. If
1063 // numLocalElements_ == 0 on this process, minMyGID_ and maxMyGID_
1064 // are both indexBase_. This is wrong, but fixing it would
1065 // require either a fancy sparse all-reduce, or a custom reduction
1066 // operator that ignores invalid values ("invalid" means
1067 // Tpetra::Details::OrdinalTraits<GO>::invalid()).
1068 //
1069 // Also, while we're at it, use the same all-reduce to figure out
1070 // if the Map is distributed. "Distributed" means that there is
1071 // at least one process with a number of local elements less than
1072 // the number of global elements.
1073 //
1074 // We're computing the min and max of all processes' GIDs using a
1075 // single MAX all-reduce, because min(x,y) = -max(-x,-y) (when x
1076 // and y are signed). (This lets us combine the min and max into
1077 // a single all-reduce.) If each process sets localDist=1 if its
1078 // number of local elements is strictly less than the number of
1079 // global elements, and localDist=0 otherwise, then a MAX
1080 // all-reduce on localDist tells us if the Map is distributed (1
1081 // if yes, 0 if no). Thus, we can append localDist onto the end
1082 // of the data and get the global result from the all-reduce.
1083 Kokkos::View<GO*, Kokkos::HostSpace> minMaxInput(Kokkos::ViewAllocateWithoutInitializing("minMaxInput"), 3);
1084 Kokkos::View<GO*, Kokkos::HostSpace> minMaxOutput(Kokkos::ViewAllocateWithoutInitializing("minMaxOutput"), 3);
1085
1086 minMaxInput[0] = std::numeric_limits<GO>::max() - minMyGID_;
1087 minMaxInput[1] = maxMyGID_;
1088 minMaxInput[2] = std::numeric_limits<GO>::max() - static_cast<GO>(numLocalElements_);
1089
1090 Teuchos::reduceAll<int, GO>(*comm_, Teuchos::REDUCE_MAX, 3, minMaxInput.data(), minMaxOutput.data());
1091
1092 minAllGID_ = std::numeric_limits<GO>::max() - minMaxOutput[0];
1093 maxAllGID_ = minMaxOutput[1];
1094 const GO minNumLocalElements = std::numeric_limits<GO>::max() - minMaxOutput[2];
1095
1096 distributed_ = (comm_->getSize() > 1 && (static_cast<GST>(minNumLocalElements) < numGlobalElements_));
1097
1098 haveGlobalConstants_ = true;
1099
1101 minAllGID_ < indexBase_,
1102 std::invalid_argument,
1103 "Tpetra::Map constructor (noncontiguous): "
1104 "Minimum global ID = "
1105 << minAllGID_ << " over all process(es) is "
1106 "less than the given indexBase = "
1107 << indexBase_ << ".");
1108}
1109
1110template <class LocalOrdinal, class GlobalOrdinal, class Node>
1112 TEUCHOS_TEST_FOR_EXCEPTION(!map.haveGlobalConstants(), std::invalid_argument, "Map needs to have global constants");
1113
1114 minAllGID_ = map.getMinAllGlobalIndex();
1115 maxAllGID_ = map.getMaxAllGlobalIndex();
1116 haveGlobalConstants_ = true;
1117 distributed_ = (getComm()->getSize() > 1) && map.distributed_;
1118}
1119
1120template <class LocalOrdinal, class GlobalOrdinal, class Node>
1122 if (!Kokkos::is_initialized()) {
1123 std::ostringstream os;
1124 os << "WARNING: Tpetra::Map destructor (~Map()) is being called after "
1125 "Kokkos::finalize() has been called. This is user error! There are "
1126 "two likely causes: "
1127 << std::endl
1128 << " 1. You have a static Tpetra::Map (or RCP or shared_ptr of a Map)"
1129 << std::endl
1130 << " 2. You declare and construct a Tpetra::Map (or RCP or shared_ptr "
1131 "of a Tpetra::Map) at the same scope in main() as Kokkos::finalize() "
1132 "or Tpetra::finalize()."
1133 << std::endl
1134 << std::endl
1135 << "Don't do either of these! Please refer to GitHib Issue #2372."
1136 << std::endl;
1137 ::Tpetra::Details::printOnce(std::cerr, os.str(),
1138 this->getComm().getRawPtr());
1139 } else {
1140 using ::Tpetra::Details::mpiIsFinalized;
1141 using ::Tpetra::Details::mpiIsInitialized;
1142 using ::Tpetra::Details::teuchosCommIsAnMpiComm;
1143
1144 Teuchos::RCP<const Teuchos::Comm<int>> comm = this->getComm();
1145 if (!comm.is_null() && teuchosCommIsAnMpiComm(*comm) &&
1146 mpiIsInitialized() && mpiIsFinalized()) {
1147 // Tpetra itself does not require MPI, even if building with
1148 // MPI. It is legal to create Tpetra objects that do not use
1149 // MPI, even in an MPI program. However, calling Tpetra stuff
1150 // after MPI_Finalize() has been called is a bad idea, since
1151 // some Tpetra defaults may use MPI if available.
1152 std::ostringstream os;
1153 os << "WARNING: Tpetra::Map destructor (~Map()) is being called after "
1154 "MPI_Finalize() has been called. This is user error! There are "
1155 "two likely causes: "
1156 << std::endl
1157 << " 1. You have a static Tpetra::Map (or RCP or shared_ptr of a Map)"
1158 << std::endl
1159 << " 2. You declare and construct a Tpetra::Map (or RCP or shared_ptr "
1160 "of a Tpetra::Map) at the same scope in main() as MPI_finalize() or "
1161 "Tpetra::finalize()."
1162 << std::endl
1163 << std::endl
1164 << "Don't do either of these! Please refer to GitHib Issue #2372."
1165 << std::endl;
1166 ::Tpetra::Details::printOnce(std::cerr, os.str(), comm.getRawPtr());
1167 }
1168 }
1169 // mfh 20 Mar 2018: We can't check Tpetra::isInitialized() yet,
1170 // because Tpetra does not yet require Tpetra::initialize /
1171 // Tpetra::finalize.
1172}
1173
1174template <class LocalOrdinal, class GlobalOrdinal, class Node>
1177 getComm().is_null(), std::logic_error,
1178 "Tpetra::Map::isOneToOne: "
1179 "getComm() returns null. Please report this bug to the Tpetra "
1180 "developers.");
1181
1182 // This is a collective operation, if it hasn't been called before.
1183 setupDirectory();
1184 return directory_->isOneToOne(*this);
1185}
1186
1187template <class LocalOrdinal, class GlobalOrdinal, class Node>
1191 if (isContiguous()) {
1192 if (globalIndex < getMinGlobalIndex() ||
1193 globalIndex > getMaxGlobalIndex()) {
1194 return Tpetra::Details::OrdinalTraits<LocalOrdinal>::invalid();
1195 }
1196 return static_cast<LocalOrdinal>(globalIndex - getMinGlobalIndex());
1197 } else if (globalIndex >= firstContiguousGID_ &&
1198 globalIndex <= lastContiguousGID_) {
1199 return static_cast<LocalOrdinal>(globalIndex - firstContiguousGID_);
1200 } else {
1201 // If the given global index is not in the table, this returns
1202 // the same value as OrdinalTraits<LocalOrdinal>::invalid().
1203 // glMapHost_ is Host and does not assume UVM
1204 lazyPushToHost();
1205 return glMapHost_.get(globalIndex);
1206 }
1207}
1208
1209template <class LocalOrdinal, class GlobalOrdinal, class Node>
1213 if (localIndex < getMinLocalIndex() || localIndex > getMaxLocalIndex()) {
1214 return Tpetra::Details::OrdinalTraits<GlobalOrdinal>::invalid();
1215 }
1216 if (isContiguous()) {
1217 return getMinGlobalIndex() + localIndex;
1218 } else {
1219 // This is a host Kokkos::View access, with no RCP or ArrayRCP
1220 // involvement. As a result, it is thread safe.
1221 //
1222 // lgMapHost_ is a host pointer; this does NOT assume UVM.
1223 lazyPushToHost();
1224 return lgMapHost_[localIndex];
1225 }
1226}
1227
1228template <class LocalOrdinal, class GlobalOrdinal, class Node>
1229bool Map<LocalOrdinal, GlobalOrdinal, Node>::getGlobalElements(
1230 const local_ordinal_type localIndices[], size_t numEntries, global_ordinal_type globalIndices[]) const {
1231 auto const minGI = getMinGlobalIndex();
1232 auto const minLI = getMinLocalIndex();
1233 auto const maxLI = getMaxLocalIndex();
1234 if (isContiguous()) {
1235 for (size_t i = 0; i < numEntries; i++) {
1236 auto lclInd = localIndices[i];
1237 if (lclInd < minLI || lclInd > maxLI) {
1238 return true;
1239 }
1240 globalIndices[i] = minGI + lclInd;
1241 }
1242 } else {
1243 // This is a host Kokkos::View access, with no RCP or ArrayRCP
1244 // involvement. As a result, it is thread safe.
1245 //
1246 // lgMapHost_ is a host pointer; this does NOT assume UVM.
1247 lazyPushToHost();
1248 for (size_t i = 0; i < numEntries; i++) {
1249 auto lclInd = localIndices[i];
1250 if (lclInd < minLI || lclInd > maxLI) {
1251 return true;
1252 }
1253 globalIndices[i] = lgMapHost_[lclInd];
1254 }
1255 }
1256 return false;
1257}
1258
1259template <class LocalOrdinal, class GlobalOrdinal, class Node>
1262 if (localIndex < getMinLocalIndex() || localIndex > getMaxLocalIndex()) {
1263 return false;
1264 } else {
1265 return true;
1266 }
1267}
1268
1269template <class LocalOrdinal, class GlobalOrdinal, class Node>
1272 return this->getLocalElement(globalIndex) !=
1273 Tpetra::Details::OrdinalTraits<LocalOrdinal>::invalid();
1274}
1275
1276template <class LocalOrdinal, class GlobalOrdinal, class Node>
1278 return uniform_;
1279}
1280
1281template <class LocalOrdinal, class GlobalOrdinal, class Node>
1283 return contiguous_;
1284}
1285
1286template <class LocalOrdinal, class GlobalOrdinal, class Node>
1289 getLocalMap() const {
1290 return local_map_type(glMap_, lgMap_, getIndexBase(),
1291 getMinGlobalIndex(), getMaxGlobalIndex(),
1292 firstContiguousGID_, lastContiguousGID_,
1293 getLocalNumElements(), isContiguous());
1294}
1295
1296template <class LocalOrdinal, class GlobalOrdinal, class Node>
1299 using Teuchos::outArg;
1300 using Teuchos::REDUCE_MIN;
1301 using Teuchos::reduceAll;
1302 //
1303 // Tests that avoid the Boolean all-reduce below by using
1304 // globally consistent quantities.
1305 //
1306 if (this == &map) {
1307 // Pointer equality on one process always implies pointer
1308 // equality on all processes, since Map is immutable.
1309 return true;
1310 } else if (getComm()->getSize() != map.getComm()->getSize()) {
1311 // The two communicators have different numbers of processes.
1312 // It's not correct to call isCompatible() in that case. This
1313 // may result in the all-reduce hanging below.
1314 return false;
1315 } else if (getGlobalNumElements() != map.getGlobalNumElements()) {
1316 // Two Maps are definitely NOT compatible if they have different
1317 // global numbers of indices.
1318 return false;
1319 } else if (isContiguous() && isUniform() &&
1320 map.isContiguous() && map.isUniform()) {
1321 // Contiguous uniform Maps with the same number of processes in
1322 // their communicators, and with the same global numbers of
1323 // indices, are always compatible.
1324 return true;
1325 } else if (!isContiguous() && !map.isContiguous() &&
1326 lgMap_.extent(0) != 0 && map.lgMap_.extent(0) != 0 &&
1327 lgMap_.data() == map.lgMap_.data()) {
1328 // Noncontiguous Maps whose global index lists are nonempty and
1329 // have the same pointer must be the same (and therefore
1330 // contiguous).
1331 //
1332 // Nonempty is important. For example, consider a communicator
1333 // with two processes, and two Maps that share this
1334 // communicator, with zero global indices on the first process,
1335 // and different nonzero numbers of global indices on the second
1336 // process. In that case, on the first process, the pointers
1337 // would both be NULL.
1338 return true;
1339 }
1340
1342 getGlobalNumElements() != map.getGlobalNumElements(), std::logic_error,
1343 "Tpetra::Map::isCompatible: There's a bug in this method. We've already "
1344 "checked that this condition is true above, but it's false here. "
1345 "Please report this bug to the Tpetra developers.");
1346
1347 // Do both Maps have the same number of indices on each process?
1348 const int locallyCompat =
1349 (getLocalNumElements() == map.getLocalNumElements()) ? 1 : 0;
1350
1351 int globallyCompat = 0;
1353 return (globallyCompat == 1);
1354}
1355
1356template <class LocalOrdinal, class GlobalOrdinal, class Node>
1359 using Teuchos::ArrayView;
1360 using GO = global_ordinal_type;
1361 using size_type = typename ArrayView<const GO>::size_type;
1362
1363 // If both Maps are contiguous, we can compare their GID ranges
1364 // easily by looking at the min and max GID on this process.
1365 // Otherwise, we'll compare their GID lists. If only one Map is
1366 // contiguous, then we only have to call getLocalElementList() on
1367 // the noncontiguous Map. (It's best to avoid calling it on a
1368 // contiguous Map, since it results in unnecessary storage that
1369 // persists for the lifetime of the Map.)
1370
1371 if (this == &map) {
1372 // Pointer equality on one process always implies pointer
1373 // equality on all processes, since Map is immutable.
1374 return true;
1375 } else if (getLocalNumElements() != map.getLocalNumElements()) {
1376 return false;
1377 } else if (getMinGlobalIndex() != map.getMinGlobalIndex() ||
1378 getMaxGlobalIndex() != map.getMaxGlobalIndex()) {
1379 return false;
1380 } else {
1381 if (isContiguous()) {
1382 if (map.isContiguous()) {
1383 return true; // min and max match, so the ranges match.
1384 } else { // *this is contiguous, but map is not contiguous
1386 !this->isContiguous() || map.isContiguous(), std::logic_error,
1387 "Tpetra::Map::locallySameAs: BUG");
1388 ArrayView<const GO> rhsElts = map.getLocalElementList();
1389 const GO minLhsGid = this->getMinGlobalIndex();
1390 const size_type numRhsElts = rhsElts.size();
1391 for (size_type k = 0; k < numRhsElts; ++k) {
1392 const GO curLhsGid = minLhsGid + static_cast<GO>(k);
1393 if (curLhsGid != rhsElts[k]) {
1394 return false; // stop on first mismatch
1395 }
1396 }
1397 return true;
1398 }
1399 } else if (map.isContiguous()) { // *this is not contiguous, but map is
1401 this->isContiguous() || !map.isContiguous(), std::logic_error,
1402 "Tpetra::Map::locallySameAs: BUG");
1403 ArrayView<const GO> lhsElts = this->getLocalElementList();
1404 const GO minRhsGid = map.getMinGlobalIndex();
1405 const size_type numLhsElts = lhsElts.size();
1406 for (size_type k = 0; k < numLhsElts; ++k) {
1407 const GO curRhsGid = minRhsGid + static_cast<GO>(k);
1408 if (curRhsGid != lhsElts[k]) {
1409 return false; // stop on first mismatch
1410 }
1411 }
1412 return true;
1413 } else if (this->lgMap_.data() == map.lgMap_.data()) {
1414 // Pointers to LID->GID "map" (actually just an array) are the
1415 // same, and the number of GIDs are the same.
1416 return this->getLocalNumElements() == map.getLocalNumElements();
1417 } else { // we actually have to compare the GIDs
1418 if (this->getLocalNumElements() != map.getLocalNumElements()) {
1419 return false; // We already checked above, but check just in case
1420 } else {
1421 using range_type = Kokkos::RangePolicy<LocalOrdinal, typename node_type::execution_space>;
1422
1423 auto lhsLclMap = getLocalMap();
1424 auto rhsLclMap = map.getLocalMap();
1425
1427 Kokkos::parallel_reduce(
1428 "Tpetra::Map::locallySameAs",
1429 range_type(0, this->getLocalNumElements()),
1431 if (lhsLclMap.getGlobalElement(lid) != rhsLclMap.getGlobalElement(lid))
1432 ++numMismatches;
1433 },
1435
1436 return (numMismatchedElements == 0);
1437 }
1438 }
1439 }
1440}
1441
1442template <class LocalOrdinal, class GlobalOrdinal, class Node>
1445 if (this == &map)
1446 return true;
1447
1448 // We are going to check if lmap1 is fitted into lmap2:
1449 // Is lmap1 (map) a subset of lmap2 (this)?
1450 // And do the first lmap1.getLocalNumElements() global elements
1451 // of lmap1,lmap2 owned on each process exactly match?
1452 auto lmap1 = map.getLocalMap();
1453 auto lmap2 = this->getLocalMap();
1454
1455 auto numLocalElements1 = lmap1.getLocalNumElements();
1456 auto numLocalElements2 = lmap2.getLocalNumElements();
1457
1459 // There are more indices in the first map on this process than in second map.
1460 return false;
1461 }
1462
1463 if (lmap1.isContiguous() && lmap2.isContiguous()) {
1464 // When both Maps are contiguous, just check the interval inclusion.
1465 return ((lmap1.getMinGlobalIndex() == lmap2.getMinGlobalIndex()) &&
1466 (lmap1.getMaxGlobalIndex() <= lmap2.getMaxGlobalIndex()));
1467 }
1468
1469 if (lmap1.getMinGlobalIndex() < lmap2.getMinGlobalIndex() ||
1470 lmap1.getMaxGlobalIndex() > lmap2.getMaxGlobalIndex()) {
1471 // The second map does not include the first map bounds, and thus some of
1472 // the first map global indices are not in the second map.
1473 return false;
1474 }
1475
1476 using LO = local_ordinal_type;
1477 using range_type =
1478 Kokkos::RangePolicy<LO, typename node_type::execution_space>;
1479
1480 // Check all elements.
1481 LO numDiff = 0;
1482 Kokkos::parallel_reduce(
1483 "isLocallyFitted",
1484 range_type(0, numLocalElements1),
1485 KOKKOS_LAMBDA(const LO i, LO& diff) {
1486 diff += (lmap1.getGlobalElement(i) != lmap2.getGlobalElement(i));
1487 },
1488 numDiff);
1489
1490 return (numDiff == 0);
1491}
1492
1493template <class LocalOrdinal, class GlobalOrdinal, class Node>
1496 using Teuchos::outArg;
1497 using Teuchos::REDUCE_MIN;
1498 using Teuchos::reduceAll;
1499 //
1500 // Tests that avoid the Boolean all-reduce below by using
1501 // globally consistent quantities.
1502 //
1503 if (this == &map) {
1504 // Pointer equality on one process always implies pointer
1505 // equality on all processes, since Map is immutable.
1506 return true;
1507 } else if (getComm()->getSize() != map.getComm()->getSize()) {
1508 // The two communicators have different numbers of processes.
1509 // It's not correct to call isSameAs() in that case. This
1510 // may result in the all-reduce hanging below.
1511 return false;
1512 } else if (getGlobalNumElements() != map.getGlobalNumElements()) {
1513 // Two Maps are definitely NOT the same if they have different
1514 // global numbers of indices.
1515 return false;
1516 } else if (haveGlobalConstants() && map.haveGlobalConstants() && (getMinAllGlobalIndex() != map.getMinAllGlobalIndex() || getMaxAllGlobalIndex() != map.getMaxAllGlobalIndex() || getIndexBase() != map.getIndexBase())) {
1517 // If the global min or max global index doesn't match, or if
1518 // the index base doesn't match, then the Maps aren't the same.
1519 return false;
1520 } else if (haveGlobalConstants() && map.haveGlobalConstants() && (isDistributed() != map.isDistributed())) {
1521 // One Map is distributed and the other is not, which means that
1522 // the Maps aren't the same.
1523 return false;
1524 } else if (isContiguous() && isUniform() &&
1525 map.isContiguous() && map.isUniform()) {
1526 // Contiguous uniform Maps with the same number of processes in
1527 // their communicators, with the same global numbers of indices,
1528 // and with matching index bases and ranges, must be the same.
1529 return true;
1530 }
1531
1532 // The two communicators must have the same number of processes,
1533 // with process ranks occurring in the same order. This uses
1534 // MPI_COMM_COMPARE. The MPI 3.1 standard (Section 6.4) says:
1535 // "Operations that access communicators are local and their
1536 // execution does not require interprocess communication."
1537 // However, just to be sure, I'll put this call after the above
1538 // tests that don't communicate.
1539 if (!::Tpetra::Details::congruent(*comm_, *(map.getComm()))) {
1540 return false;
1541 }
1542
1543 // If we get this far, we need to check local properties and then
1544 // communicate local sameness across all processes.
1545 const int isSame_lcl = locallySameAs(map) ? 1 : 0;
1546
1547 // Return true if and only if all processes report local sameness.
1548 int isSame_gbl = 0;
1550 return isSame_gbl == 1;
1551}
1552
1553namespace { // (anonymous)
1554template <class LO, class GO, class DT>
1555class FillLgMap {
1556 public:
1557 FillLgMap(const Kokkos::View<GO*, DT>& lgMap,
1558 const GO startGid)
1559 : lgMap_(lgMap)
1560 , startGid_(startGid) {
1561 Kokkos::RangePolicy<LO, typename DT::execution_space>
1562 range(static_cast<LO>(0), static_cast<LO>(lgMap.size()));
1563 Kokkos::parallel_for(range, *this);
1564 }
1565
1566 KOKKOS_INLINE_FUNCTION void operator()(const LO& lid) const {
1567 lgMap_(lid) = startGid_ + static_cast<GO>(lid);
1568 }
1569
1570 private:
1571 const Kokkos::View<GO*, DT> lgMap_;
1572 const GO startGid_;
1573};
1574
1575} // namespace
1576
1577template <class LocalOrdinal, class GlobalOrdinal, class Node>
1578typename Map<LocalOrdinal, GlobalOrdinal, Node>::global_indices_array_type
1580 using std::endl;
1581 using LO = local_ordinal_type;
1582 using GO = global_ordinal_type;
1583 using const_lg_view_type = decltype(lgMap_);
1584 using lg_view_type = typename const_lg_view_type::non_const_type;
1585 const bool debug = Details::Behavior::debug("Map");
1586 const bool verbose = Details::Behavior::verbose("Map");
1587
1588 std::unique_ptr<std::string> prefix;
1589 if (verbose) {
1591 comm_.getRawPtr(), "Map", "getMyGlobalIndices");
1592 std::ostringstream os;
1593 os << *prefix << "Start" << endl;
1594 std::cerr << os.str();
1595 }
1596
1597 // If the local-to-global mapping doesn't exist yet, and if we
1598 // have local entries, then create and fill the local-to-global
1599 // mapping.
1601 lgMap_.extent(0) == 0 && numLocalElements_ > 0;
1602
1604 if (verbose) {
1605 std::ostringstream os;
1606 os << *prefix << "Need to create lgMap" << endl;
1607 std::cerr << os.str();
1608 }
1609 if (debug) {
1610 // The local-to-global mapping should have been set up already
1611 // for a noncontiguous map.
1612 TEUCHOS_TEST_FOR_EXCEPTION(!isContiguous(), std::logic_error,
1613 "Tpetra::Map::getMyGlobalIndices: The local-to-global "
1614 "mapping (lgMap_) should have been set up already for a "
1615 "noncontiguous Map. Please report this bug to the Tpetra "
1616 "developers.");
1617 }
1618 const LO numElts = static_cast<LO>(getLocalNumElements());
1619
1620 using Kokkos::view_alloc;
1621 using Kokkos::WithoutInitializing;
1622 lg_view_type lgMap("lgMap3", numElts);
1623 if (verbose) {
1624 std::ostringstream os;
1625 os << *prefix << "Fill lgMap" << endl;
1626 std::cerr << os.str();
1627 }
1629
1630 if (verbose) {
1631 std::ostringstream os;
1632 os << *prefix << "Copy lgMap to lgMapHost" << endl;
1633 std::cerr << os.str();
1634 }
1635
1636 auto lgMapHost = Kokkos::create_mirror_view(Kokkos::HostSpace(), lgMap);
1637 // DEEP_COPY REVIEW - DEVICE-TO-HOST
1639 Kokkos::deep_copy(exec_instance, lgMapHost, lgMap);
1640
1641 // There's a non-trivial chance we'll grab this on the host,
1642 // so let's make sure the copy finishes
1643 exec_instance.fence();
1644
1645 // "Commit" the local-to-global lookup table we filled in above.
1646 lgMap_ = lgMap;
1647 lgMapHost_ = lgMapHost;
1648 } else {
1649 lazyPushToHost();
1650 }
1651
1652 if (verbose) {
1653 std::ostringstream os;
1654 os << *prefix << "Done" << endl;
1655 std::cerr << os.str();
1656 }
1657 return lgMapHost_;
1658}
1659
1660template <class LocalOrdinal, class GlobalOrdinal, class Node>
1661typename Map<LocalOrdinal, GlobalOrdinal, Node>::global_indices_array_device_type
1663 using std::endl;
1664 using LO = local_ordinal_type;
1665 using GO = global_ordinal_type;
1666 using const_lg_view_type = decltype(lgMap_);
1667 using lg_view_type = typename const_lg_view_type::non_const_type;
1668 const bool debug = Details::Behavior::debug("Map");
1669 const bool verbose = Details::Behavior::verbose("Map");
1670
1671 std::unique_ptr<std::string> prefix;
1672 if (verbose) {
1674 comm_.getRawPtr(), "Map", "getMyGlobalIndicesDevice");
1675 std::ostringstream os;
1676 os << *prefix << "Start" << endl;
1677 std::cerr << os.str();
1678 }
1679
1680 // If the local-to-global mapping doesn't exist yet, and if we
1681 // have local entries, then create and fill the local-to-global
1682 // mapping.
1684 lgMap_.extent(0) == 0 && numLocalElements_ > 0;
1685
1687 if (verbose) {
1688 std::ostringstream os;
1689 os << *prefix << "Need to create lgMap" << endl;
1690 std::cerr << os.str();
1691 }
1692 if (debug) {
1693 // The local-to-global mapping should have been set up already
1694 // for a noncontiguous map.
1695 TEUCHOS_TEST_FOR_EXCEPTION(!isContiguous(), std::logic_error,
1696 "Tpetra::Map::getMyGlobalIndices: The local-to-global "
1697 "mapping (lgMap_) should have been set up already for a "
1698 "noncontiguous Map. Please report this bug to the Tpetra "
1699 "developers.");
1700 }
1701 const LO numElts = static_cast<LO>(getLocalNumElements());
1702
1703 using Kokkos::view_alloc;
1704 using Kokkos::WithoutInitializing;
1705 lg_view_type lgMap("lgMap4", numElts);
1706 if (verbose) {
1707 std::ostringstream os;
1708 os << *prefix << "Fill lgMap" << endl;
1709 std::cerr << os.str();
1710 }
1712
1713 // "Commit" the local-to-global lookup table we filled in above.
1714 lgMap_ = lgMap;
1715 }
1716
1717 if (verbose) {
1718 std::ostringstream os;
1719 os << *prefix << "Done" << endl;
1720 std::cerr << os.str();
1721 }
1722 return lgMap_;
1723}
1724
1725template <class LocalOrdinal, class GlobalOrdinal, class Node>
1726Teuchos::ArrayView<const GlobalOrdinal>
1728 using GO = global_ordinal_type;
1729
1730 // If the local-to-global mapping doesn't exist yet, and if we
1731 // have local entries, then create and fill the local-to-global
1732 // mapping.
1733 (void)this->getMyGlobalIndices();
1734
1735 // This does NOT assume UVM; lgMapHost_ is a host pointer.
1736 lazyPushToHost();
1737 const GO* lgMapHostRawPtr = lgMapHost_.data();
1738 // The third argument forces ArrayView not to try to track memory
1739 // in a debug build. We have to use it because the memory does
1740 // not belong to a Teuchos memory management class.
1741 return Teuchos::ArrayView<const GO>(
1743 lgMapHost_.extent(0),
1744 Teuchos::RCP_DISABLE_NODE_LOOKUP);
1745}
1746
1747template <class LocalOrdinal, class GlobalOrdinal, class Node>
1749 return distributed_;
1750}
1751
1752template <class LocalOrdinal, class GlobalOrdinal, class Node>
1754 using Teuchos::TypeNameTraits;
1755 std::ostringstream os;
1756
1757 os << "Tpetra::Map: {"
1758 << "LocalOrdinalType: " << TypeNameTraits<LocalOrdinal>::name()
1759 << ", GlobalOrdinalType: " << TypeNameTraits<GlobalOrdinal>::name()
1760 << ", NodeType: " << TypeNameTraits<Node>::name();
1761 if (this->getObjectLabel() != "") {
1762 os << ", Label: \"" << this->getObjectLabel() << "\"";
1763 }
1764 os << ", Global number of entries: " << getGlobalNumElements()
1765 << ", Number of processes: " << getComm()->getSize()
1766 << ", Uniform: " << (isUniform() ? "true" : "false")
1767 << ", Contiguous: " << (isContiguous() ? "true" : "false")
1768 << ", Distributed: " << (isDistributed() ? "true" : "false")
1769 << "}";
1770 return os.str();
1771}
1772
1777template <class LocalOrdinal, class GlobalOrdinal, class Node>
1778std::string
1780 localDescribeToString(const Teuchos::EVerbosityLevel vl) const {
1781 using LO = local_ordinal_type;
1782 using std::endl;
1783
1784 // This preserves current behavior of Map.
1785 if (vl < Teuchos::VERB_HIGH) {
1786 return std::string();
1787 }
1788 auto outStringP = Teuchos::rcp(new std::ostringstream());
1789 Teuchos::RCP<Teuchos::FancyOStream> outp =
1790 Teuchos::getFancyOStream(outStringP);
1791 Teuchos::FancyOStream& out = *outp;
1792
1793 auto comm = this->getComm();
1794 const int myRank = comm->getRank();
1795 const int numProcs = comm->getSize();
1796 out << "Process " << myRank << " of " << numProcs << ":" << endl;
1797 Teuchos::OSTab tab1(out);
1798
1799 const LO numEnt = static_cast<LO>(this->getLocalNumElements());
1800 out << "My number of entries: " << numEnt << endl
1801 << "My minimum global index: " << this->getMinGlobalIndex() << endl
1802 << "My maximum global index: " << this->getMaxGlobalIndex() << endl;
1803
1804 if (vl == Teuchos::VERB_EXTREME) {
1805 out << "My global indices: [";
1806 const LO minLclInd = this->getMinLocalIndex();
1807 for (LO k = 0; k < numEnt; ++k) {
1808 out << minLclInd + this->getGlobalElement(k);
1809 if (k + 1 < numEnt) {
1810 out << ", ";
1811 }
1812 }
1813 out << "]" << endl;
1814 }
1815
1816 out.flush(); // make sure the ostringstream got everything
1817 return outStringP->str();
1818}
1819
1820template <class LocalOrdinal, class GlobalOrdinal, class Node>
1822 describe(Teuchos::FancyOStream& out,
1823 const Teuchos::EVerbosityLevel verbLevel) const {
1824 using std::endl;
1825 using Teuchos::TypeNameTraits;
1826 using Teuchos::VERB_DEFAULT;
1827 using Teuchos::VERB_HIGH;
1828 using Teuchos::VERB_LOW;
1829 using Teuchos::VERB_NONE;
1830 using LO = local_ordinal_type;
1831 using GO = global_ordinal_type;
1832 const Teuchos::EVerbosityLevel vl =
1834
1835 if (vl == VERB_NONE) {
1836 return; // don't print anything
1837 }
1838 // If this Map's Comm is null, then the Map does not participate
1839 // in collective operations with the other processes. In that
1840 // case, it is not even legal to call this method. The reasonable
1841 // thing to do in that case is nothing.
1842 auto comm = this->getComm();
1843 if (comm.is_null()) {
1844 return;
1845 }
1846 const int myRank = comm->getRank();
1847 const int numProcs = comm->getSize();
1848
1849 // Only Process 0 should touch the output stream, but this method
1850 // in general may need to do communication. Thus, we may need to
1851 // preserve the current tab level across multiple "if (myRank ==
1852 // 0) { ... }" inner scopes. This is why we sometimes create
1853 // OSTab instances by pointer, instead of by value. We only need
1854 // to create them by pointer if the tab level must persist through
1855 // multiple inner scopes.
1856 Teuchos::RCP<Teuchos::OSTab> tab0, tab1;
1857
1858 if (myRank == 0) {
1859 // At every verbosity level but VERB_NONE, Process 0 prints.
1860 // By convention, describe() always begins with a tab before
1861 // printing.
1862 tab0 = Teuchos::rcp(new Teuchos::OSTab(out));
1863 out << "\"Tpetra::Map\":" << endl;
1864 tab1 = Teuchos::rcp(new Teuchos::OSTab(out));
1865 {
1866 out << "Template parameters:" << endl;
1867 Teuchos::OSTab tab2(out);
1868 out << "LocalOrdinal: " << TypeNameTraits<LO>::name() << endl
1869 << "GlobalOrdinal: " << TypeNameTraits<GO>::name() << endl
1870 << "Node: " << TypeNameTraits<Node>::name() << endl;
1871 }
1872 const std::string label = this->getObjectLabel();
1873 if (label != "") {
1874 out << "Label: \"" << label << "\"" << endl;
1875 }
1876 out << "Global number of entries: " << getGlobalNumElements() << endl
1877 << "Minimum global index: " << getMinAllGlobalIndex() << endl
1878 << "Maximum global index: " << getMaxAllGlobalIndex() << endl
1879 << "Index base: " << getIndexBase() << endl
1880 << "Number of processes: " << numProcs << endl
1881 << "Uniform: " << (isUniform() ? "true" : "false") << endl
1882 << "Contiguous: " << (isContiguous() ? "true" : "false") << endl
1883 << "Distributed: " << (isDistributed() ? "true" : "false") << endl;
1884 }
1885
1886 // This is collective over the Map's communicator.
1887 if (vl >= VERB_HIGH) { // VERB_HIGH or VERB_EXTREME
1888 const std::string lclStr = this->localDescribeToString(vl);
1890 }
1891}
1892
1893template <class LocalOrdinal, class GlobalOrdinal, class Node>
1894Teuchos::RCP<const Map<LocalOrdinal, GlobalOrdinal, Node>>
1896 replaceCommWithSubset(const Teuchos::RCP<const Teuchos::Comm<int>>& newComm) const {
1897 using Teuchos::RCP;
1898 using Teuchos::rcp;
1899 using GST = global_size_t;
1900 using LO = local_ordinal_type;
1901 using GO = global_ordinal_type;
1902 using map_type = Map<LO, GO, Node>;
1903
1904 // mfh 26 Mar 2013: The lazy way to do this is simply to recreate
1905 // the Map by calling its ordinary public constructor, using the
1906 // original Map's data. This only involves O(1) all-reduces over
1907 // the new communicator, which in the common case only includes a
1908 // small number of processes.
1909
1910 // Create the Map to return.
1911 if (newComm.is_null() || newComm->getSize() < 1) {
1912 return Teuchos::null; // my process does not participate in the new Map
1913 } else if (newComm->getSize() == 1) {
1914 lazyPushToHost();
1915
1916 // The case where the new communicator has only one process is
1917 // easy. We don't have to communicate to get all the
1918 // information we need. Use the default comm to create the new
1919 // Map, then fill in all the fields directly.
1920 RCP<map_type> newMap(new map_type());
1921
1922 newMap->comm_ = newComm;
1923 // mfh 07 Oct 2016: Preserve original behavior, even though the
1924 // original index base may no longer be the globally min global
1925 // index. See #616 for why this doesn't matter so much anymore.
1926 newMap->indexBase_ = this->indexBase_;
1927 newMap->numGlobalElements_ = this->numLocalElements_;
1928 newMap->numLocalElements_ = this->numLocalElements_;
1929 newMap->minMyGID_ = this->minMyGID_;
1930 newMap->maxMyGID_ = this->maxMyGID_;
1931 newMap->minAllGID_ = this->minMyGID_;
1932 newMap->maxAllGID_ = this->maxMyGID_;
1933 newMap->firstContiguousGID_ = this->firstContiguousGID_;
1934 newMap->lastContiguousGID_ = this->lastContiguousGID_;
1935 newMap->haveGlobalConstants_ = this->haveGlobalConstants_;
1936 // Since the new communicator has only one process, neither
1937 // uniformity nor contiguity have changed.
1938 newMap->uniform_ = this->uniform_;
1939 newMap->contiguous_ = this->contiguous_;
1940 // The new communicator only has one process, so the new Map is
1941 // not distributed.
1942 newMap->distributed_ = false;
1943 newMap->lgMap_ = this->lgMap_;
1944 newMap->lgMapHost_ = this->lgMapHost_;
1945 newMap->glMap_ = this->glMap_;
1946 newMap->glMapHost_ = this->glMapHost_;
1947 // It's OK not to initialize the new Map's Directory.
1948 // This is initialized lazily, on first call to getRemoteIndexList.
1949
1950 return newMap;
1951 } else { // newComm->getSize() != 1
1952 // Even if the original Map is contiguous, the new Map might not
1953 // be, especially if the excluded processes have ranks != 0 or
1954 // newComm->getSize()-1. The common case for this method is to
1955 // exclude many (possibly even all but one) processes, so it
1956 // likely doesn't pay to do the global communication (over the
1957 // original communicator) to figure out whether we can optimize
1958 // the result Map. Thus, we just set up the result Map as
1959 // noncontiguous.
1960 //
1961 // TODO (mfh 07 Oct 2016) We don't actually need to reconstruct
1962 // the global-to-local table, etc. Optimize this code path to
1963 // avoid unnecessary local work.
1964
1965 // Make Map (re)compute the global number of elements.
1966 const GST RECOMPUTE = Tpetra::Details::OrdinalTraits<GST>::invalid();
1967 // TODO (mfh 07 Oct 2016) If we use any Map constructor, we have
1968 // to use the noncontiguous Map constructor, since the new Map
1969 // might not be contiguous. Even if the old Map was contiguous,
1970 // some process in the "middle" might have been excluded. If we
1971 // want to avoid local work, we either have to do the setup by
1972 // hand, or write a new Map constructor.
1973#if 1
1974 // The disabled code here throws the following exception in
1975 // Map's replaceCommWithSubset test:
1976 //
1977 // Throw test that evaluated to true: static_cast<unsigned long long> (numKeys) > static_cast<unsigned long long> (::Kokkos::ArithTraits<ValueType>::max ())
1978 // 10:
1979 // 10: Tpetra::Details::FixedHashTable: The number of keys -3 is greater than the maximum representable ValueType value 2147483647. This means that it is not possible to use this constructor.
1980 // 10: Process 3: origComm->replaceCommWithSubset(subsetComm) threw an exception: /scratch/prj/Trilinos/Trilinos/packages/tpetra/core/src/Tpetra_Details_FixedHashTable_def.hpp:1044:
1981
1982 auto lgMap = this->getMyGlobalIndices();
1983 using size_type =
1984 typename std::decay<decltype(lgMap.extent(0))>::type;
1985 const size_type lclNumInds =
1986 static_cast<size_type>(this->getLocalNumElements());
1987 using Teuchos::TypeNameTraits;
1988 TEUCHOS_TEST_FOR_EXCEPTION(lgMap.extent(0) != lclNumInds, std::logic_error,
1989 "Tpetra::Map::replaceCommWithSubset: Result of getMyGlobalIndices() "
1990 "has length "
1991 << lgMap.extent(0) << " (of type " << TypeNameTraits<size_type>::name() << ") != this->getLocalNumElements()"
1992 " = "
1993 << this->getLocalNumElements() << ". The latter, upon being "
1994 "cast to size_type = "
1996 "becomes "
1997 << lclNumInds << ". Please report this bug to the Tpetra "
1998 "developers.");
1999#else
2000 Teuchos::ArrayView<const GO> lgMap = this->getLocalElementList();
2001#endif // 1
2002
2003 const GO indexBase = this->getIndexBase();
2004 // map stores HostSpace of CudaSpace but constructor is still CudaUVMSpace
2005 auto lgMap_device = Kokkos::create_mirror_view_and_copy(device_type(), lgMap);
2006 return rcp(new map_type(RECOMPUTE, lgMap_device, indexBase, newComm));
2007 }
2008}
2009
2010template <class LocalOrdinal, class GlobalOrdinal, class Node>
2011Teuchos::RCP<const Map<LocalOrdinal, GlobalOrdinal, Node>>
2013 removeEmptyProcesses() const {
2014 Tpetra::Details::ProfilingRegion pr("Map::removeEmptyProcesses");
2015 using Teuchos::Comm;
2016 using Teuchos::null;
2017 using Teuchos::outArg;
2018 using Teuchos::RCP;
2019 using Teuchos::rcp;
2020 using Teuchos::REDUCE_MIN;
2021 using Teuchos::reduceAll;
2022
2023 // Create the new communicator. split() returns a valid
2024 // communicator on all processes. On processes where color == 0,
2025 // ignore the result. Passing key == 0 tells MPI to order the
2026 // processes in the new communicator by their rank in the old
2027 // communicator.
2028 const int color = (numLocalElements_ == 0) ? 0 : 1;
2029 // MPI_Comm_split must be called collectively over the original
2030 // communicator. We can't just call it on processes with color
2031 // one, even though we will ignore its result on processes with
2032 // color zero.
2033 RCP<const Comm<int>> newComm = comm_->split(color, 0);
2034 if (color == 0) {
2035 newComm = null;
2036 }
2037
2038 // Create the Map to return.
2039 if (newComm.is_null()) {
2040 return null; // my process does not participate in the new Map
2041 } else {
2042 RCP<Map> map = rcp(new Map());
2043
2044 map->comm_ = newComm;
2045 map->indexBase_ = indexBase_;
2046 map->numGlobalElements_ = numGlobalElements_;
2047 map->numLocalElements_ = numLocalElements_;
2048 map->minMyGID_ = minMyGID_;
2049 map->maxMyGID_ = maxMyGID_;
2050 map->minAllGID_ = minAllGID_;
2051 map->maxAllGID_ = maxAllGID_;
2052 map->firstContiguousGID_ = firstContiguousGID_;
2053 map->lastContiguousGID_ = lastContiguousGID_;
2054 map->haveGlobalConstants_ = haveGlobalConstants_;
2055
2056 // Uniformity and contiguity have not changed. The directory
2057 // has changed, but we've taken care of that above.
2058 map->uniform_ = uniform_;
2059 map->contiguous_ = contiguous_;
2060
2061 // If the original Map was NOT distributed, then the new Map
2062 // cannot be distributed.
2063 //
2064 // If the number of processes in the new communicator is 1, then
2065 // the new Map is not distributed.
2066 //
2067 // Otherwise, we have to check the new Map using an all-reduce
2068 // (over the new communicator). For example, the original Map
2069 // may have had some processes with zero elements, and all other
2070 // processes with the same number of elements as in the whole
2071 // Map. That Map is technically distributed, because of the
2072 // processes with zero elements. Removing those processes would
2073 // make the new Map locally replicated.
2074 if (!distributed_ || newComm->getSize() == 1) {
2075 map->distributed_ = false;
2076 if (newComm->getSize() == 1) {
2077 map->minAllGID_ = map->minMyGID_;
2078 map->maxAllGID_ = map->maxMyGID_;
2079 map->haveGlobalConstants_ = true;
2080 }
2081 } else {
2082 const int iOwnAllGids = (numLocalElements_ == numGlobalElements_) ? 1 : 0;
2083 int allProcsOwnAllGids = 0;
2085 map->distributed_ = (allProcsOwnAllGids == 1) ? false : true;
2086 }
2087
2088 map->lgMap_ = lgMap_;
2089 map->lgMapHost_ = lgMapHost_;
2090 map->glMap_ = glMap_;
2091 map->glMapHost_ = glMapHost_;
2092
2093 // Map's default constructor creates an uninitialized Directory.
2094 // The Directory will be initialized on demand in
2095 // getRemoteIndexList().
2096 //
2097 // FIXME (mfh 26 Mar 2013) It should be possible to "filter" the
2098 // directory more efficiently than just recreating it. If
2099 // directory recreation proves a bottleneck, we can always
2100 // revisit this. On the other hand, Directory creation is only
2101 // collective over the new, presumably much smaller
2102 // communicator, so it may not be worth the effort to optimize.
2103
2104 return map;
2105 }
2106}
2107
2108template <class LocalOrdinal, class GlobalOrdinal, class Node>
2111 directory_.is_null(), std::logic_error,
2112 "Tpetra::Map::setupDirectory: "
2113 "The Directory is null. "
2114 "Please report this bug to the Tpetra developers.");
2115
2116 // Only create the Directory if it hasn't been created yet.
2117 // This is a collective operation.
2118 if (!directory_->initialized()) {
2119 // non-contiguous directory needs global constants
2120 if (isDistributed() && !isUniform() && !isContiguous())
2121 computeGlobalConstants();
2122 directory_->initialize(*this);
2123 }
2124}
2125
2126template <class LocalOrdinal, class GlobalOrdinal, class Node>
2129 getRemoteIndexList(const Teuchos::ArrayView<const GlobalOrdinal>& GIDs,
2130 const Teuchos::ArrayView<int>& PIDs,
2131 const Teuchos::ArrayView<LocalOrdinal>& LIDs) const {
2133 using std::endl;
2134 using Tpetra::Details::OrdinalTraits;
2135 using size_type = Teuchos::ArrayView<int>::size_type;
2136
2137 const bool verbose = Details::Behavior::verbose("Map");
2139 std::unique_ptr<std::string> prefix;
2140 if (verbose) {
2141 prefix = Details::createPrefix(comm_.getRawPtr(),
2142 "Map", "getRemoteIndexList(GIDs,PIDs,LIDs)");
2143 std::ostringstream os;
2144 os << *prefix << "Start: ";
2145 verbosePrintArray(os, GIDs, "GIDs", maxNumToPrint);
2146 os << endl;
2147 std::cerr << os.str();
2148 }
2149
2150 // Empty Maps (i.e., containing no indices on any processes in the
2151 // Map's communicator) are perfectly valid. In that case, if the
2152 // input GID list is nonempty, we fill the output arrays with
2153 // invalid values, and return IDNotPresent to notify the caller.
2154 // It's perfectly valid to give getRemoteIndexList GIDs that the
2155 // Map doesn't own. SubmapImport test 2 needs this functionality.
2156 if (getGlobalNumElements() == 0) {
2157 if (GIDs.size() == 0) {
2158 if (verbose) {
2159 std::ostringstream os;
2160 os << *prefix << "Done; both Map & input are empty" << endl;
2161 std::cerr << os.str();
2162 }
2163 return AllIDsPresent; // trivially
2164 } else {
2165 if (verbose) {
2166 std::ostringstream os;
2167 os << *prefix << "Done: Map is empty on all processes, "
2168 "so all output PIDs & LIDs are invalid (-1)."
2169 << endl;
2170 std::cerr << os.str();
2171 }
2172 for (size_type k = 0; k < PIDs.size(); ++k) {
2174 }
2175 for (size_type k = 0; k < LIDs.size(); ++k) {
2177 }
2178 return IDNotPresent;
2179 }
2180 }
2181
2182 // getRemoteIndexList must be called collectively, and Directory
2183 // initialization is collective too, so it's OK to initialize the
2184 // Directory on demand.
2185
2186 if (verbose) {
2187 std::ostringstream os;
2188 os << *prefix << "Call setupDirectory" << endl;
2189 std::cerr << os.str();
2190 }
2191 setupDirectory();
2192 if (verbose) {
2193 std::ostringstream os;
2194 os << *prefix << "Call directory_->getDirectoryEntries" << endl;
2195 std::cerr << os.str();
2196 }
2198 directory_->getDirectoryEntries(*this, GIDs, PIDs, LIDs);
2199 if (verbose) {
2200 std::ostringstream os;
2201 os << *prefix << "Done; getDirectoryEntries returned "
2202 << (retVal == IDNotPresent ? "IDNotPresent" : "AllIDsPresent")
2203 << "; ";
2204 verbosePrintArray(os, PIDs, "PIDs", maxNumToPrint);
2205 os << ", ";
2206 verbosePrintArray(os, LIDs, "LIDs", maxNumToPrint);
2207 os << endl;
2208 std::cerr << os.str();
2209 }
2210 return retVal;
2211}
2212
2213template <class LocalOrdinal, class GlobalOrdinal, class Node>
2216 getRemoteIndexList(const Teuchos::ArrayView<const GlobalOrdinal>& GIDs,
2217 const Teuchos::ArrayView<int>& PIDs) const {
2219 using std::endl;
2220
2221 const bool verbose = Details::Behavior::verbose("Map");
2223 std::unique_ptr<std::string> prefix;
2224 if (verbose) {
2225 prefix = Details::createPrefix(comm_.getRawPtr(),
2226 "Map", "getRemoteIndexList(GIDs,PIDs)");
2227 std::ostringstream os;
2228 os << *prefix << "Start: ";
2229 verbosePrintArray(os, GIDs, "GIDs", maxNumToPrint);
2230 os << endl;
2231 std::cerr << os.str();
2232 }
2233
2234 if (getGlobalNumElements() == 0) {
2235 if (GIDs.size() == 0) {
2236 if (verbose) {
2237 std::ostringstream os;
2238 os << *prefix << "Done; both Map & input are empty" << endl;
2239 std::cerr << os.str();
2240 }
2241 return AllIDsPresent; // trivially
2242 } else {
2243 if (verbose) {
2244 std::ostringstream os;
2245 os << *prefix << "Done: Map is empty on all processes, "
2246 "so all output PIDs are invalid (-1)."
2247 << endl;
2248 std::cerr << os.str();
2249 }
2250 for (Teuchos::ArrayView<int>::size_type k = 0; k < PIDs.size(); ++k) {
2251 PIDs[k] = Tpetra::Details::OrdinalTraits<int>::invalid();
2252 }
2253 return IDNotPresent;
2254 }
2255 }
2256
2257 // getRemoteIndexList must be called collectively, and Directory
2258 // initialization is collective too, so it's OK to initialize the
2259 // Directory on demand.
2260
2261 if (verbose) {
2262 std::ostringstream os;
2263 os << *prefix << "Call setupDirectory" << endl;
2264 std::cerr << os.str();
2265 }
2266 setupDirectory();
2267 if (verbose) {
2268 std::ostringstream os;
2269 os << *prefix << "Call directory_->getDirectoryEntries" << endl;
2270 std::cerr << os.str();
2271 }
2273 directory_->getDirectoryEntries(*this, GIDs, PIDs);
2274 if (verbose) {
2275 std::ostringstream os;
2276 os << *prefix << "Done; getDirectoryEntries returned "
2277 << (retVal == IDNotPresent ? "IDNotPresent" : "AllIDsPresent")
2278 << "; ";
2279 verbosePrintArray(os, PIDs, "PIDs", maxNumToPrint);
2280 os << endl;
2281 std::cerr << os.str();
2282 }
2283 return retVal;
2284}
2285
2286template <class LocalOrdinal, class GlobalOrdinal, class Node>
2288 using exec_space = typename Node::device_type::execution_space;
2289 if (lgMap_.extent(0) != lgMapHost_.extent(0)) {
2290 Tpetra::Details::ProfilingRegion pr("Map::lazyPushToHost() - pushing data");
2291 // NOTE: We check lgMap_ and not glMap_, since the latter can
2292 // be somewhat error prone for contiguous maps
2293
2294 // create_mirror_view preserves const-ness. create_mirror does not
2295 auto lgMap_host = Kokkos::create_mirror(Kokkos::HostSpace(), lgMap_);
2296
2297 // Since this was computed on the default stream, we can copy on the stream and then fence
2298 // the stream
2299 Kokkos::deep_copy(exec_space(), lgMap_host, lgMap_);
2300 exec_space().fence();
2301 lgMapHost_ = lgMap_host;
2302
2303 // Make host version - when memory spaces match these just do trivial assignment
2304 glMapHost_ = global_to_local_table_host_type(glMap_);
2305 }
2306}
2307
2308template <class LocalOrdinal, class GlobalOrdinal, class Node>
2309Teuchos::RCP<const Teuchos::Comm<int>>
2311 return comm_;
2312}
2313
2314template <class LocalOrdinal, class GlobalOrdinal, class Node>
2316 checkIsDist() const {
2317 using std::endl;
2318 using Teuchos::as;
2319 using Teuchos::outArg;
2320 using Teuchos::REDUCE_MIN;
2321 using Teuchos::reduceAll;
2322
2323 const bool verbose = Details::Behavior::verbose("Map");
2324 std::unique_ptr<std::string> prefix;
2325 if (verbose) {
2327 comm_.getRawPtr(), "Map", "checkIsDist");
2328 std::ostringstream os;
2329 os << *prefix << "Start" << endl;
2330 std::cerr << os.str();
2331 }
2332
2333 bool global = false;
2334 if (comm_->getSize() > 1) {
2335 // The communicator has more than one process, but that doesn't
2336 // necessarily mean the Map is distributed.
2337 int localRep = 0;
2338 if (numGlobalElements_ == as<global_size_t>(numLocalElements_)) {
2339 // The number of local elements on this process equals the
2340 // number of global elements.
2341 //
2342 // NOTE (mfh 22 Nov 2011) Does this still work if there were
2343 // duplicates in the global ID list on input (the third Map
2344 // constructor), so that the number of local elements (which
2345 // are not duplicated) on this process could be less than the
2346 // number of global elements, even if this process owns all
2347 // the elements?
2348 localRep = 1;
2349 }
2350 int allLocalRep;
2351 reduceAll<int, int>(*comm_, REDUCE_MIN, localRep, outArg(allLocalRep));
2352 if (allLocalRep != 1) {
2353 // At least one process does not own all the elements.
2354 // This makes the Map a distributed Map.
2355 global = true;
2356 }
2357 }
2358 // If the communicator has only one process, then the Map is not
2359 // distributed.
2360
2361 if (verbose) {
2362 std::ostringstream os;
2363 os << *prefix << "Done; global=" << (global ? "true" : "false")
2364 << endl;
2365 std::cerr << os.str();
2366 }
2367 return global;
2368}
2369
2370} // namespace Tpetra
2371
2372template <class LocalOrdinal, class GlobalOrdinal>
2373Teuchos::RCP<const Tpetra::Map<LocalOrdinal, GlobalOrdinal>>
2374Tpetra::createLocalMap(const size_t numElements,
2375 const Teuchos::RCP<const Teuchos::Comm<int>>& comm) {
2376 typedef LocalOrdinal LO;
2377 typedef GlobalOrdinal GO;
2378 using NT = typename ::Tpetra::Map<LO, GO>::node_type;
2379 return createLocalMapWithNode<LO, GO, NT>(numElements, comm);
2380}
2381
2382template <class LocalOrdinal, class GlobalOrdinal>
2383Teuchos::RCP<const Tpetra::Map<LocalOrdinal, GlobalOrdinal>>
2384Tpetra::createUniformContigMap(const global_size_t numElements,
2385 const Teuchos::RCP<const Teuchos::Comm<int>>& comm) {
2386 typedef LocalOrdinal LO;
2387 typedef GlobalOrdinal GO;
2388 using NT = typename ::Tpetra::Map<LO, GO>::node_type;
2389 return createUniformContigMapWithNode<LO, GO, NT>(numElements, comm);
2390}
2391
2392template <class LocalOrdinal, class GlobalOrdinal, class Node>
2393Teuchos::RCP<const Tpetra::Map<LocalOrdinal, GlobalOrdinal, Node>>
2394Tpetra::createUniformContigMapWithNode(const global_size_t numElements,
2395 const Teuchos::RCP<const Teuchos::Comm<int>>& comm) {
2396 using Teuchos::rcp;
2398 const GlobalOrdinal indexBase = static_cast<GlobalOrdinal>(0);
2399
2400 return rcp(new map_type(numElements, indexBase, comm, GloballyDistributed));
2401}
2402
2403template <class LocalOrdinal, class GlobalOrdinal, class Node>
2404Teuchos::RCP<const Tpetra::Map<LocalOrdinal, GlobalOrdinal, Node>>
2405Tpetra::createLocalMapWithNode(const size_t numElements,
2406 const Teuchos::RCP<const Teuchos::Comm<int>>& comm) {
2407 using Teuchos::rcp;
2410 const GlobalOrdinal indexBase = 0;
2411 const global_size_t globalNumElts = static_cast<global_size_t>(numElements);
2412
2413 return rcp(new map_type(globalNumElts, indexBase, comm, LocallyReplicated));
2414}
2415
2416template <class LocalOrdinal, class GlobalOrdinal, class Node>
2417Teuchos::RCP<const Tpetra::Map<LocalOrdinal, GlobalOrdinal, Node>>
2419 const size_t localNumElements,
2420 const Teuchos::RCP<const Teuchos::Comm<int>>& comm) {
2421 using Teuchos::rcp;
2423 const GlobalOrdinal indexBase = 0;
2424
2425 return rcp(new map_type(numElements, localNumElements, indexBase, comm));
2426}
2427
2428template <class LocalOrdinal, class GlobalOrdinal>
2429Teuchos::RCP<const Tpetra::Map<LocalOrdinal, GlobalOrdinal>>
2431 const size_t localNumElements,
2432 const Teuchos::RCP<const Teuchos::Comm<int>>& comm) {
2433 typedef LocalOrdinal LO;
2434 typedef GlobalOrdinal GO;
2435 using NT = typename Tpetra::Map<LO, GO>::node_type;
2436
2437 return Tpetra::createContigMapWithNode<LO, GO, NT>(numElements, localNumElements, comm);
2438}
2439
2440template <class LocalOrdinal, class GlobalOrdinal>
2441Teuchos::RCP<const Tpetra::Map<LocalOrdinal, GlobalOrdinal>>
2442Tpetra::createNonContigMap(const Teuchos::ArrayView<const GlobalOrdinal>& elementList,
2443 const Teuchos::RCP<const Teuchos::Comm<int>>& comm) {
2444 typedef LocalOrdinal LO;
2445 typedef GlobalOrdinal GO;
2446 using NT = typename Tpetra::Map<LO, GO>::node_type;
2447
2448 return Tpetra::createNonContigMapWithNode<LO, GO, NT>(elementList, comm);
2449}
2450
2451template <class LocalOrdinal, class GlobalOrdinal, class Node>
2452Teuchos::RCP<const Tpetra::Map<LocalOrdinal, GlobalOrdinal, Node>>
2453Tpetra::createNonContigMapWithNode(const Teuchos::ArrayView<const GlobalOrdinal>& elementList,
2454 const Teuchos::RCP<const Teuchos::Comm<int>>& comm) {
2455 using Teuchos::rcp;
2457 using GST = Tpetra::global_size_t;
2458 const GST INV = Tpetra::Details::OrdinalTraits<GST>::invalid();
2459 // FIXME (mfh 22 Jul 2016) This is what I found here, but maybe this
2460 // shouldn't be zero, given that the index base is supposed to equal
2461 // the globally min global index?
2462 const GlobalOrdinal indexBase = 0;
2463
2464 return rcp(new map_type(INV, elementList, indexBase, comm));
2465}
2466
2467template <class LO, class GO, class NT>
2468Teuchos::RCP<const Tpetra::Map<LO, GO, NT>>
2469Tpetra::createOneToOne(const Teuchos::RCP<const Tpetra::Map<LO, GO, NT>>& M) {
2470 using Details::verbosePrintArray;
2471 using std::cerr;
2472 using std::endl;
2473 using Teuchos::Array;
2474 using Teuchos::ArrayView;
2475 using Teuchos::as;
2476 using Teuchos::rcp;
2477 using map_type = Tpetra::Map<LO, GO, NT>;
2478 using GST = global_size_t;
2479
2480 const bool verbose = Details::Behavior::verbose("Map");
2481 std::unique_ptr<std::string> prefix;
2482 if (verbose) {
2483 auto comm = M.is_null() ? Teuchos::null : M->getComm();
2484 prefix = Details::createPrefix(
2485 comm.getRawPtr(), "createOneToOne(Map)");
2486 std::ostringstream os;
2487 os << *prefix << "Start" << endl;
2488 cerr << os.str();
2489 }
2490 const size_t maxNumToPrint = verbose ? Details::Behavior::verbosePrintCountThreshold() : size_t(0);
2491 const GST GINV = Tpetra::Details::OrdinalTraits<GST>::invalid();
2492 const int myRank = M->getComm()->getRank();
2493
2494 // Bypasses for special cases where either M is known to be
2495 // one-to-one, or the one-to-one version of M is easy to compute.
2496 // This is why we take M as an RCP, not as a const reference -- so
2497 // that we can return M itself if it is 1-to-1.
2498 if (!M->isDistributed()) {
2499 // For a locally replicated Map, we assume that users want to push
2500 // all the GIDs to Process 0.
2501
2502 // mfh 05 Nov 2013: getGlobalNumElements() does indeed return what
2503 // you think it should return, in this special case of a locally
2504 // replicated contiguous Map.
2505 const GST numGlobalEntries = M->getGlobalNumElements();
2506 if (M->isContiguous()) {
2507 const size_t numLocalEntries =
2508 (myRank == 0) ? as<size_t>(numGlobalEntries) : size_t(0);
2509 if (verbose) {
2510 std::ostringstream os;
2511 os << *prefix << "Input is locally replicated & contiguous; "
2512 "numLocalEntries="
2513 << numLocalEntries << endl;
2514 cerr << os.str();
2515 }
2516 auto retMap =
2517 rcp(new map_type(numGlobalEntries, numLocalEntries,
2518 M->getIndexBase(), M->getComm()));
2519 if (verbose) {
2520 std::ostringstream os;
2521 os << *prefix << "Done" << endl;
2522 cerr << os.str();
2523 }
2524 return retMap;
2525 } else {
2526 if (verbose) {
2527 std::ostringstream os;
2528 os << *prefix << "Input is locally replicated & noncontiguous"
2529 << endl;
2530 cerr << os.str();
2531 }
2532 ArrayView<const GO> myGids =
2533 (myRank == 0) ? M->getLocalElementList() : Teuchos::null;
2534 auto retMap =
2535 rcp(new map_type(GINV, myGids(), M->getIndexBase(),
2536 M->getComm()));
2537 if (verbose) {
2538 std::ostringstream os;
2539 os << *prefix << "Done" << endl;
2540 cerr << os.str();
2541 }
2542 return retMap;
2543 }
2544 } else if (M->isContiguous()) {
2545 if (verbose) {
2546 std::ostringstream os;
2547 os << *prefix << "Input is distributed & contiguous" << endl;
2548 cerr << os.str();
2549 }
2550 // Contiguous, distributed Maps are one-to-one by construction.
2551 // (Locally replicated Maps can be contiguous.)
2552 return M;
2553 } else {
2554 if (verbose) {
2555 std::ostringstream os;
2556 os << *prefix << "Input is distributed & noncontiguous" << endl;
2557 cerr << os.str();
2558 }
2560 const size_t numMyElems = M->getLocalNumElements();
2561 ArrayView<const GO> myElems = M->getLocalElementList();
2562 Array<int> owner_procs_vec(numMyElems);
2563
2564 if (verbose) {
2565 std::ostringstream os;
2566 os << *prefix << "Call Directory::getDirectoryEntries: ";
2567 verbosePrintArray(os, myElems, "GIDs", maxNumToPrint);
2568 os << endl;
2569 cerr << os.str();
2570 }
2571 directory.getDirectoryEntries(*M, myElems, owner_procs_vec());
2572 if (verbose) {
2573 std::ostringstream os;
2574 os << *prefix << "getDirectoryEntries result: ";
2575 verbosePrintArray(os, owner_procs_vec, "PIDs", maxNumToPrint);
2576 os << endl;
2577 cerr << os.str();
2578 }
2579
2580 Array<GO> myOwned_vec(numMyElems);
2581 size_t numMyOwnedElems = 0;
2582 for (size_t i = 0; i < numMyElems; ++i) {
2583 const GO GID = myElems[i];
2584 const int owner = owner_procs_vec[i];
2585
2586 if (myRank == owner) {
2587 myOwned_vec[numMyOwnedElems++] = GID;
2588 }
2589 }
2590 myOwned_vec.resize(numMyOwnedElems);
2591
2592 if (verbose) {
2593 std::ostringstream os;
2594 os << *prefix << "Create Map: ";
2595 verbosePrintArray(os, myOwned_vec, "GIDs", maxNumToPrint);
2596 os << endl;
2597 cerr << os.str();
2598 }
2599 auto retMap = rcp(new map_type(GINV, myOwned_vec(),
2600 M->getIndexBase(), M->getComm()));
2601 if (verbose) {
2602 std::ostringstream os;
2603 os << *prefix << "Done" << endl;
2604 cerr << os.str();
2605 }
2606 return retMap;
2607 }
2608}
2609
2610template <class LocalOrdinal, class GlobalOrdinal, class Node>
2611Teuchos::RCP<const Tpetra::Map<LocalOrdinal, GlobalOrdinal, Node>>
2614 using Details::Behavior;
2615 using Details::verbosePrintArray;
2616 using std::cerr;
2617 using std::endl;
2618 using Teuchos::Array;
2619 using Teuchos::ArrayView;
2620 using Teuchos::RCP;
2621 using Teuchos::rcp;
2622 using Teuchos::toString;
2623 using LO = LocalOrdinal;
2624 using GO = GlobalOrdinal;
2625 using map_type = Tpetra::Map<LO, GO, Node>;
2626
2627 const bool verbose = Behavior::verbose("Map");
2628 std::unique_ptr<std::string> prefix;
2629 if (verbose) {
2630 auto comm = M.is_null() ? Teuchos::null : M->getComm();
2631 prefix = Details::createPrefix(
2632 comm.getRawPtr(), "createOneToOne(Map,TieBreak)");
2633 std::ostringstream os;
2634 os << *prefix << "Start" << endl;
2635 cerr << os.str();
2636 }
2637 const size_t maxNumToPrint = verbose ? Behavior::verbosePrintCountThreshold() : size_t(0);
2638
2639 // FIXME (mfh 20 Feb 2013) We should have a bypass for contiguous
2640 // Maps (which are 1-to-1 by construction).
2641
2643 if (verbose) {
2644 std::ostringstream os;
2645 os << *prefix << "Initialize Directory" << endl;
2646 cerr << os.str();
2647 }
2648 directory.initialize(*M, tie_break);
2649 if (verbose) {
2650 std::ostringstream os;
2651 os << *prefix << "Done initializing Directory" << endl;
2652 cerr << os.str();
2653 }
2654 size_t numMyElems = M->getLocalNumElements();
2655 ArrayView<const GO> myElems = M->getLocalElementList();
2656 Array<int> owner_procs_vec(numMyElems);
2657 if (verbose) {
2658 std::ostringstream os;
2659 os << *prefix << "Call Directory::getDirectoryEntries: ";
2660 verbosePrintArray(os, myElems, "GIDs", maxNumToPrint);
2661 os << endl;
2662 cerr << os.str();
2663 }
2664 directory.getDirectoryEntries(*M, myElems, owner_procs_vec());
2665 if (verbose) {
2666 std::ostringstream os;
2667 os << *prefix << "getDirectoryEntries result: ";
2668 verbosePrintArray(os, owner_procs_vec, "PIDs", maxNumToPrint);
2669 os << endl;
2670 cerr << os.str();
2671 }
2672
2673 const int myRank = M->getComm()->getRank();
2674 Array<GO> myOwned_vec(numMyElems);
2675 size_t numMyOwnedElems = 0;
2676 for (size_t i = 0; i < numMyElems; ++i) {
2677 const GO GID = myElems[i];
2678 const int owner = owner_procs_vec[i];
2679 if (myRank == owner) {
2680 myOwned_vec[numMyOwnedElems++] = GID;
2681 }
2682 }
2683 myOwned_vec.resize(numMyOwnedElems);
2684
2685 // FIXME (mfh 08 May 2014) The above Directory should be perfectly
2686 // valid for the new Map. Why can't we reuse it?
2687 const global_size_t GINV =
2688 Tpetra::Details::OrdinalTraits<global_size_t>::invalid();
2689 if (verbose) {
2690 std::ostringstream os;
2691 os << *prefix << "Create Map: ";
2692 verbosePrintArray(os, myOwned_vec, "GIDs", maxNumToPrint);
2693 os << endl;
2694 cerr << os.str();
2695 }
2696 RCP<const map_type> retMap(new map_type(GINV, myOwned_vec(), M->getIndexBase(),
2697 M->getComm()));
2698 if (verbose) {
2699 std::ostringstream os;
2700 os << *prefix << "Done" << endl;
2701 cerr << os.str();
2702 }
2703 return retMap;
2704}
2705
2706namespace Tpetra::Details {
2707
2708template <class pids_view_type>
2709struct SortToFit {
2710 int myRank;
2711 pids_view_type pids;
2712
2713 SortToFit(int _myRank, pids_view_type _pids)
2714 : myRank(_myRank)
2715 , pids(_pids) {}
2716
2717 KOKKOS_FUNCTION
2718 bool operator()(size_t i, size_t j) const {
2719 if (pids(i) == myRank) {
2720 if (pids(j) == myRank)
2721 return i < j;
2722 else
2723 return true;
2724 } else {
2725 if (pids(j) == myRank)
2726 return false;
2727 else
2728 return i < j;
2729 }
2730 }
2731};
2732
2733} // namespace Tpetra::Details
2734
2735template <class LO, class GO, class NT>
2736Teuchos::RCP<const Tpetra::Map<LO, GO, NT>>
2738 Teuchos::RCP<const Tpetra::Map<LO, GO, NT>> constM = M;
2740
2741 const int locallyFitted = M->isLocallyFitted(*owned_node_map);
2742 int globallyLocallyFitted = 0;
2743 reduceAll(*M->getComm(), Teuchos::REDUCE_MIN, locallyFitted, Teuchos::outArg(globallyLocallyFitted));
2744
2745 if (globallyLocallyFitted == 0) {
2746 using pid_type = int;
2747
2748 const pid_type myRank = M->getComm()->getRank();
2749 const size_t numMyElems = M->getLocalNumElements();
2750
2751 Kokkos::View<pid_type*, typename NT::memory_space> pids("pids", numMyElems);
2752 {
2753 auto gids_vec = M->getLocalElementList();
2754 Teuchos::Array<pid_type> pids_vec(numMyElems);
2755 M->getRemoteIndexList(gids_vec, pids_vec);
2756 Kokkos::View<pid_type*, Kokkos::HostSpace, Kokkos::MemoryTraits<Kokkos::Unmanaged>> pids_h(pids_vec.data(), pids_vec.size());
2757 Kokkos::deep_copy(pids, pids_h);
2758 }
2759
2760 auto gids = M->getMyGlobalIndicesDevice();
2761
2762 auto policy = Kokkos::RangePolicy<size_t, typename NT::execution_space>(0, numMyElems);
2763
2764 Kokkos::View<size_t*, typename NT::memory_space> idx(Kokkos::ViewAllocateWithoutInitializing("idx"), numMyElems);
2765 Kokkos::parallel_for(
2766 policy, KOKKOS_LAMBDA(const size_t i) { idx(i) = i; });
2767
2768 Tpetra::Details::SortToFit cmp(myRank, pids);
2769 Kokkos::sort(typename NT::execution_space(), idx, cmp);
2770
2771 Kokkos::View<GO*, typename NT::memory_space> new_gids(Kokkos::ViewAllocateWithoutInitializing("new_gids"), numMyElems);
2772 Kokkos::parallel_for(
2773 policy, KOKKOS_LAMBDA(const size_t i) { new_gids(i) = gids(idx(i)); });
2774
2775 Teuchos::RCP<const Tpetra::Map<LO, GO, NT>> shared_node_map =
2776 Teuchos::rcp(new Tpetra::Map<LO, GO, NT>(M->getGlobalNumElements(),
2777 new_gids,
2778 M->getIndexBase(),
2779 M->getComm()));
2780 M.swap(shared_node_map);
2781 }
2782
2783 return owned_node_map;
2784}
2785
2786//
2787// Explicit instantiation macro
2788//
2789// Must be expanded from within the Tpetra namespace!
2790//
2791
2793
2794#define TPETRA_MAP_INSTANT(LO, GO, NODE) \
2795 \
2796 template class Map<LO, GO, NODE>; \
2797 \
2798 template Teuchos::RCP<const Map<LO, GO, NODE>> \
2799 createLocalMapWithNode<LO, GO, NODE>(const size_t numElements, \
2800 const Teuchos::RCP<const Teuchos::Comm<int>>& comm); \
2801 \
2802 template Teuchos::RCP<const Map<LO, GO, NODE>> \
2803 createContigMapWithNode<LO, GO, NODE>(const global_size_t numElements, \
2804 const size_t localNumElements, \
2805 const Teuchos::RCP<const Teuchos::Comm<int>>& comm); \
2806 \
2807 template Teuchos::RCP<const Map<LO, GO, NODE>> \
2808 createNonContigMapWithNode(const Teuchos::ArrayView<const GO>& elementList, \
2809 const Teuchos::RCP<const Teuchos::Comm<int>>& comm); \
2810 \
2811 template Teuchos::RCP<const Map<LO, GO, NODE>> \
2812 createUniformContigMapWithNode<LO, GO, NODE>(const global_size_t numElements, \
2813 const Teuchos::RCP<const Teuchos::Comm<int>>& comm); \
2814 \
2815 template Teuchos::RCP<const Map<LO, GO, NODE>> \
2816 createOneToOne(const Teuchos::RCP<const Map<LO, GO, NODE>>& M); \
2817 \
2818 template Teuchos::RCP<const Map<LO, GO, NODE>> \
2819 createOneToOne(const Teuchos::RCP<const Map<LO, GO, NODE>>& M, \
2820 const Tpetra::Details::TieBreak<LO, GO>& tie_break); \
2821 \
2822 template Teuchos::RCP<const Map<LO, GO, NODE>> \
2823 createOneToOneAndMakeOverlappingMapFitted(Teuchos::RCP<const Map<LO, GO, NODE>>& M);
2824
2826#define TPETRA_MAP_INSTANT_DEFAULTNODE(LO, GO) \
2827 template Teuchos::RCP<const Map<LO, GO>> \
2828 createLocalMap<LO, GO>(const size_t, const Teuchos::RCP<const Teuchos::Comm<int>>&); \
2829 \
2830 template Teuchos::RCP<const Map<LO, GO>> \
2831 createContigMap<LO, GO>(global_size_t, size_t, \
2832 const Teuchos::RCP<const Teuchos::Comm<int>>&); \
2833 \
2834 template Teuchos::RCP<const Map<LO, GO>> \
2835 createNonContigMap(const Teuchos::ArrayView<const GO>&, \
2836 const Teuchos::RCP<const Teuchos::Comm<int>>&); \
2837 \
2838 template Teuchos::RCP<const Map<LO, GO>> \
2839 createUniformContigMap<LO, GO>(const global_size_t, \
2840 const Teuchos::RCP<const Teuchos::Comm<int>>&);
2841
2842#endif // TPETRA_MAP_DEF_HPP
Functions for initializing and finalizing Tpetra.
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 Tpetra::Details::extractMpiCommFromTeuchos.
Declaration of a function that prints strings from each process.
Declaration of Tpetra::Details::iallreduce.
Declaration of Tpetra::Details::initializeKokkos.
Declaration of Tpetra::Details::printOnce.
Declaration of the Tpetra::Map class and related nonmember constructors.
Stand-alone utility functions and macros.
Struct that holds views of the contents of a CrsMatrix.
Description of Tpetra's behavior.
static void reject_unrecognized_env_vars()
Search the environment for TPETRA_ variables and reject unrecognized ones.
static bool debug()
Whether Tpetra is in debug mode.
static bool verbose()
Whether Tpetra is in verbose mode.
static size_t verbosePrintCountThreshold()
Number of entries below which arrays, lists, etc. will be printed in debug mode.
"Local" part of Map suitable for Kokkos kernels.
Interface for breaking ties in ownership.
Implement mapping from global ID to process ID and local ID.
A parallel distribution of indices over processes.
bool isDistributed() const
Whether this Map is globally distributed or locally replicated.
bool isOneToOne() const
Whether the Map is one to one.
std::string description() const
Implementation of Teuchos::Describable.
Teuchos::ArrayView< const global_ordinal_type > getLocalElementList() const
Return a NONOWNING view of the global indices owned by this process.
::Tpetra::Details::FixedHashTable< global_ordinal_type, local_ordinal_type, device_type > global_to_local_table_type
Type of a mapping from global IDs to local IDs.
global_ordinal_type getGlobalElement(local_ordinal_type localIndex) const
The global index corresponding to the given local index.
Node node_type
Legacy typedef that will go away at some point.
Kokkos::View< const global_ordinal_type *, Kokkos::LayoutLeft, device_type > lgMap_
A mapping from local IDs to global IDs.
Map()
Default constructor (that does nothing).
GlobalOrdinal global_ordinal_type
The type of global indices.
LookupStatus getRemoteIndexList(const Teuchos::ArrayView< const global_ordinal_type > &GIDList, const Teuchos::ArrayView< int > &nodeIDList, const Teuchos::ArrayView< local_ordinal_type > &LIDList) const
Return the process ranks and corresponding local indices for the given global indices.
bool isNodeLocalElement(local_ordinal_type localIndex) const
Whether the given local index is valid for this Map on the calling process.
bool isUniform() const
Whether the range of global indices is uniform.
Teuchos::RCP< const Teuchos::Comm< int > > getComm() const
Accessors for the Teuchos::Comm and Kokkos Node objects.
typename device_type::execution_space execution_space
The Kokkos execution space.
LO local_ordinal_type
The type of local indices.
Teuchos::RCP< const Map< local_ordinal_type, global_ordinal_type, Node > > removeEmptyProcesses() const
Advanced methods.
void lazyPushToHost() const
Push the device data to host, if needed.
void copyGlobalConstants(const Map< local_ordinal_type, global_ordinal_type, Node > &map)
Copy global constants from a different map.
bool isCompatible(const Map< local_ordinal_type, global_ordinal_type, Node > &map) const
True if and only if map is compatible with this Map.
bool locallySameAs(const Map< local_ordinal_type, global_ordinal_type, node_type > &map) const
Is this Map locally the same as the input Map?
bool isLocallyFitted(const Map< local_ordinal_type, global_ordinal_type, Node > &map) const
True if and only if map is locally fitted to this Map.
virtual ~Map()
Destructor (virtual for memory safety of derived classes).
global_indices_array_device_type getMyGlobalIndicesDevice() const
Return a view of the global indices owned by this process on the Map's device.
local_ordinal_type getLocalElement(global_ordinal_type globalIndex) const
The local index corresponding to the given global index.
Teuchos::RCP< const Map< local_ordinal_type, global_ordinal_type, Node > > replaceCommWithSubset(const Teuchos::RCP< const Teuchos::Comm< int > > &newComm) const
Replace this Map's communicator with a subset communicator.
bool isContiguous() const
True if this Map is distributed contiguously, else false.
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.
bool isNodeGlobalElement(global_ordinal_type globalIndex) const
Whether the given global index is owned by this Map on the calling process.
bool isSameAs(const Map< local_ordinal_type, global_ordinal_type, Node > &map) const
True if and only if map is identical to this Map.
global_to_local_table_type glMap_
A mapping from global IDs to local IDs.
local_map_type getLocalMap() const
Get the LocalMap for Kokkos-Kernels.
global_indices_array_type getMyGlobalIndices() const
Return a view of the global indices owned by this process.
void computeGlobalConstants() const
Compute global constants for the map. This method needs to be called collectively over all processes ...
typename Node::device_type device_type
This class' Kokkos::Device specialization.
Implementation details of Tpetra.
Nonmember function that computes a residual Computes R = B - A * X.
void verbosePrintArray(std::ostream &out, const ArrayType &x, const char name[], const size_t maxNumToPrint)
Print min(x.size(), maxNumToPrint) entries of x.
void printOnce(std::ostream &out, const std::string &s, const Teuchos::Comm< int > *comm)
Print on one process of the given communicator, or at least try to do so (if MPI is not initialized).
std::unique_ptr< std::string > createPrefix(const int myRank, const char prefix[])
Create string prefix for each line of verbose output.
bool congruent(const Teuchos::Comm< int > &comm1, const Teuchos::Comm< int > &comm2)
Whether the two communicators are congruent.
void initializeKokkos(int *argc, char ***argv, int myRank)
Initialize Kokkos, using command-line arguments (if any) given to Teuchos::GlobalMPISession.
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.
Teuchos::RCP< const Map< LocalOrdinal, GlobalOrdinal > > createLocalMap(const size_t numElements, const Teuchos::RCP< const Teuchos::Comm< int > > &comm)
Nonmember constructor for a locally replicated Map with the default Kokkos Node.
Teuchos::RCP< const Map< LocalOrdinal, GlobalOrdinal > > createUniformContigMap(const global_size_t numElements, const Teuchos::RCP< const Teuchos::Comm< int > > &comm)
Non-member constructor for a uniformly distributed, contiguous Map with the default Kokkos Node.
Teuchos::RCP< const Map< LocalOrdinal, GlobalOrdinal > > createNonContigMap(const Teuchos::ArrayView< const GlobalOrdinal > &elementList, const Teuchos::RCP< const Teuchos::Comm< int > > &comm)
Nonmember constructor for a non-contiguous Map using the default Kokkos::Device type.
Teuchos::RCP< const Map< LocalOrdinal, GlobalOrdinal, Node > > createUniformContigMapWithNode(const global_size_t numElements, const Teuchos::RCP< const Teuchos::Comm< int > > &comm)
Non-member constructor for a uniformly distributed, contiguous Map with a user-specified Kokkos Node.
Teuchos::RCP< const Tpetra::Map< LO, GO, NT > > createOneToOneAndMakeOverlappingMapFitted(Teuchos::RCP< const Tpetra::Map< LO, GO, NT > > &M)
Creates a one-to-one version of the given Map where each GID lives on only one process....
LookupStatus
Return status of Map remote index lookup (getRemoteIndexList()).
Teuchos::RCP< const Map< LocalOrdinal, GlobalOrdinal > > createContigMap(const global_size_t numElements, const size_t localNumElements, const Teuchos::RCP< const Teuchos::Comm< int > > &comm)
Non-member constructor for a (potentially) non-uniformly distributed, contiguous Map using the defaul...
size_t global_size_t
Global size_t object.
Teuchos::RCP< const Map< LocalOrdinal, GlobalOrdinal, Node > > createOneToOne(const Teuchos::RCP< const Map< LocalOrdinal, GlobalOrdinal, Node > > &M)
Nonmember constructor for a contiguous Map with user-defined weights and a user-specified,...
Teuchos::RCP< const Map< LocalOrdinal, GlobalOrdinal, Node > > createLocalMapWithNode(const size_t numElements, const Teuchos::RCP< const Teuchos::Comm< int > > &comm)
Nonmember constructor for a locally replicated Map with a specified Kokkos Node.
Teuchos::RCP< const Map< LocalOrdinal, GlobalOrdinal, Node > > createNonContigMapWithNode(const Teuchos::ArrayView< const GlobalOrdinal > &elementList, const Teuchos::RCP< const Teuchos::Comm< int > > &comm)
Nonmember constructor for a noncontiguous Map with a user-specified, possibly nondefault Kokkos Node ...
LocalGlobal
Enum for local versus global allocation of Map entries.
Teuchos::RCP< const Map< LocalOrdinal, GlobalOrdinal, Node > > createContigMapWithNode(const global_size_t numElements, const size_t localNumElements, const Teuchos::RCP< const Teuchos::Comm< int > > &comm)
Nonmember constructor for a (potentially) nonuniformly distributed, contiguous Map for a user-specifi...