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 if (!Kokkos::is_initialized()) {
1113 std::ostringstream os;
1114 os << "WARNING: Tpetra::Map destructor (~Map()) is being called after "
1115 "Kokkos::finalize() has been called. This is user error! There are "
1116 "two likely causes: "
1117 << std::endl
1118 << " 1. You have a static Tpetra::Map (or RCP or shared_ptr of a Map)"
1119 << std::endl
1120 << " 2. You declare and construct a Tpetra::Map (or RCP or shared_ptr "
1121 "of a Tpetra::Map) at the same scope in main() as Kokkos::finalize() "
1122 "or Tpetra::finalize()."
1123 << std::endl
1124 << std::endl
1125 << "Don't do either of these! Please refer to GitHib Issue #2372."
1126 << std::endl;
1127 ::Tpetra::Details::printOnce(std::cerr, os.str(),
1128 this->getComm().getRawPtr());
1129 } else {
1130 using ::Tpetra::Details::mpiIsFinalized;
1131 using ::Tpetra::Details::mpiIsInitialized;
1132 using ::Tpetra::Details::teuchosCommIsAnMpiComm;
1133
1134 Teuchos::RCP<const Teuchos::Comm<int>> comm = this->getComm();
1135 if (!comm.is_null() && teuchosCommIsAnMpiComm(*comm) &&
1136 mpiIsInitialized() && mpiIsFinalized()) {
1137 // Tpetra itself does not require MPI, even if building with
1138 // MPI. It is legal to create Tpetra objects that do not use
1139 // MPI, even in an MPI program. However, calling Tpetra stuff
1140 // after MPI_Finalize() has been called is a bad idea, since
1141 // some Tpetra defaults may use MPI if available.
1142 std::ostringstream os;
1143 os << "WARNING: Tpetra::Map destructor (~Map()) is being called after "
1144 "MPI_Finalize() has been called. This is user error! There are "
1145 "two likely causes: "
1146 << std::endl
1147 << " 1. You have a static Tpetra::Map (or RCP or shared_ptr of a Map)"
1148 << std::endl
1149 << " 2. You declare and construct a Tpetra::Map (or RCP or shared_ptr "
1150 "of a Tpetra::Map) at the same scope in main() as MPI_finalize() or "
1151 "Tpetra::finalize()."
1152 << std::endl
1153 << std::endl
1154 << "Don't do either of these! Please refer to GitHib Issue #2372."
1155 << std::endl;
1156 ::Tpetra::Details::printOnce(std::cerr, os.str(), comm.getRawPtr());
1157 }
1158 }
1159 // mfh 20 Mar 2018: We can't check Tpetra::isInitialized() yet,
1160 // because Tpetra does not yet require Tpetra::initialize /
1161 // Tpetra::finalize.
1162}
1163
1164template <class LocalOrdinal, class GlobalOrdinal, class Node>
1167 getComm().is_null(), std::logic_error,
1168 "Tpetra::Map::isOneToOne: "
1169 "getComm() returns null. Please report this bug to the Tpetra "
1170 "developers.");
1171
1172 // This is a collective operation, if it hasn't been called before.
1173 setupDirectory();
1174 return directory_->isOneToOne(*this);
1175}
1176
1177template <class LocalOrdinal, class GlobalOrdinal, class Node>
1181 if (isContiguous()) {
1182 if (globalIndex < getMinGlobalIndex() ||
1183 globalIndex > getMaxGlobalIndex()) {
1184 return Tpetra::Details::OrdinalTraits<LocalOrdinal>::invalid();
1185 }
1186 return static_cast<LocalOrdinal>(globalIndex - getMinGlobalIndex());
1187 } else if (globalIndex >= firstContiguousGID_ &&
1188 globalIndex <= lastContiguousGID_) {
1189 return static_cast<LocalOrdinal>(globalIndex - firstContiguousGID_);
1190 } else {
1191 // If the given global index is not in the table, this returns
1192 // the same value as OrdinalTraits<LocalOrdinal>::invalid().
1193 // glMapHost_ is Host and does not assume UVM
1194 lazyPushToHost();
1195 return glMapHost_.get(globalIndex);
1196 }
1197}
1198
1199template <class LocalOrdinal, class GlobalOrdinal, class Node>
1203 if (localIndex < getMinLocalIndex() || localIndex > getMaxLocalIndex()) {
1204 return Tpetra::Details::OrdinalTraits<GlobalOrdinal>::invalid();
1205 }
1206 if (isContiguous()) {
1207 return getMinGlobalIndex() + localIndex;
1208 } else {
1209 // This is a host Kokkos::View access, with no RCP or ArrayRCP
1210 // involvement. As a result, it is thread safe.
1211 //
1212 // lgMapHost_ is a host pointer; this does NOT assume UVM.
1213 lazyPushToHost();
1214 return lgMapHost_[localIndex];
1215 }
1216}
1217
1218template <class LocalOrdinal, class GlobalOrdinal, class Node>
1219bool Map<LocalOrdinal, GlobalOrdinal, Node>::getGlobalElements(
1220 const local_ordinal_type localIndices[], size_t numEntries, global_ordinal_type globalIndices[]) const {
1221 auto const minGI = getMinGlobalIndex();
1222 auto const minLI = getMinLocalIndex();
1223 auto const maxLI = getMaxLocalIndex();
1224 if (isContiguous()) {
1225 for (size_t i = 0; i < numEntries; i++) {
1226 auto lclInd = localIndices[i];
1227 if (lclInd < minLI || lclInd > maxLI) {
1228 return true;
1229 }
1230 globalIndices[i] = minGI + lclInd;
1231 }
1232 } else {
1233 // This is a host Kokkos::View access, with no RCP or ArrayRCP
1234 // involvement. As a result, it is thread safe.
1235 //
1236 // lgMapHost_ is a host pointer; this does NOT assume UVM.
1237 lazyPushToHost();
1238 for (size_t i = 0; i < numEntries; i++) {
1239 auto lclInd = localIndices[i];
1240 if (lclInd < minLI || lclInd > maxLI) {
1241 return true;
1242 }
1243 globalIndices[i] = lgMapHost_[lclInd];
1244 }
1245 }
1246 return false;
1247}
1248
1249template <class LocalOrdinal, class GlobalOrdinal, class Node>
1252 if (localIndex < getMinLocalIndex() || localIndex > getMaxLocalIndex()) {
1253 return false;
1254 } else {
1255 return true;
1256 }
1257}
1258
1259template <class LocalOrdinal, class GlobalOrdinal, class Node>
1262 return this->getLocalElement(globalIndex) !=
1263 Tpetra::Details::OrdinalTraits<LocalOrdinal>::invalid();
1264}
1265
1266template <class LocalOrdinal, class GlobalOrdinal, class Node>
1268 return uniform_;
1269}
1270
1271template <class LocalOrdinal, class GlobalOrdinal, class Node>
1273 return contiguous_;
1274}
1275
1276template <class LocalOrdinal, class GlobalOrdinal, class Node>
1279 getLocalMap() const {
1280 return local_map_type(glMap_, lgMap_, getIndexBase(),
1281 getMinGlobalIndex(), getMaxGlobalIndex(),
1282 firstContiguousGID_, lastContiguousGID_,
1283 getLocalNumElements(), isContiguous());
1284}
1285
1286template <class LocalOrdinal, class GlobalOrdinal, class Node>
1289 using Teuchos::outArg;
1290 using Teuchos::REDUCE_MIN;
1291 using Teuchos::reduceAll;
1292 //
1293 // Tests that avoid the Boolean all-reduce below by using
1294 // globally consistent quantities.
1295 //
1296 if (this == &map) {
1297 // Pointer equality on one process always implies pointer
1298 // equality on all processes, since Map is immutable.
1299 return true;
1300 } else if (getComm()->getSize() != map.getComm()->getSize()) {
1301 // The two communicators have different numbers of processes.
1302 // It's not correct to call isCompatible() in that case. This
1303 // may result in the all-reduce hanging below.
1304 return false;
1305 } else if (getGlobalNumElements() != map.getGlobalNumElements()) {
1306 // Two Maps are definitely NOT compatible if they have different
1307 // global numbers of indices.
1308 return false;
1309 } else if (isContiguous() && isUniform() &&
1310 map.isContiguous() && map.isUniform()) {
1311 // Contiguous uniform Maps with the same number of processes in
1312 // their communicators, and with the same global numbers of
1313 // indices, are always compatible.
1314 return true;
1315 } else if (!isContiguous() && !map.isContiguous() &&
1316 lgMap_.extent(0) != 0 && map.lgMap_.extent(0) != 0 &&
1317 lgMap_.data() == map.lgMap_.data()) {
1318 // Noncontiguous Maps whose global index lists are nonempty and
1319 // have the same pointer must be the same (and therefore
1320 // contiguous).
1321 //
1322 // Nonempty is important. For example, consider a communicator
1323 // with two processes, and two Maps that share this
1324 // communicator, with zero global indices on the first process,
1325 // and different nonzero numbers of global indices on the second
1326 // process. In that case, on the first process, the pointers
1327 // would both be NULL.
1328 return true;
1329 }
1330
1332 getGlobalNumElements() != map.getGlobalNumElements(), std::logic_error,
1333 "Tpetra::Map::isCompatible: There's a bug in this method. We've already "
1334 "checked that this condition is true above, but it's false here. "
1335 "Please report this bug to the Tpetra developers.");
1336
1337 // Do both Maps have the same number of indices on each process?
1338 const int locallyCompat =
1339 (getLocalNumElements() == map.getLocalNumElements()) ? 1 : 0;
1340
1341 int globallyCompat = 0;
1343 return (globallyCompat == 1);
1344}
1345
1346template <class LocalOrdinal, class GlobalOrdinal, class Node>
1349 using Teuchos::ArrayView;
1350 using GO = global_ordinal_type;
1351 using size_type = typename ArrayView<const GO>::size_type;
1352
1353 // If both Maps are contiguous, we can compare their GID ranges
1354 // easily by looking at the min and max GID on this process.
1355 // Otherwise, we'll compare their GID lists. If only one Map is
1356 // contiguous, then we only have to call getLocalElementList() on
1357 // the noncontiguous Map. (It's best to avoid calling it on a
1358 // contiguous Map, since it results in unnecessary storage that
1359 // persists for the lifetime of the Map.)
1360
1361 if (this == &map) {
1362 // Pointer equality on one process always implies pointer
1363 // equality on all processes, since Map is immutable.
1364 return true;
1365 } else if (getLocalNumElements() != map.getLocalNumElements()) {
1366 return false;
1367 } else if (getMinGlobalIndex() != map.getMinGlobalIndex() ||
1368 getMaxGlobalIndex() != map.getMaxGlobalIndex()) {
1369 return false;
1370 } else {
1371 if (isContiguous()) {
1372 if (map.isContiguous()) {
1373 return true; // min and max match, so the ranges match.
1374 } else { // *this is contiguous, but map is not contiguous
1376 !this->isContiguous() || map.isContiguous(), std::logic_error,
1377 "Tpetra::Map::locallySameAs: BUG");
1378 ArrayView<const GO> rhsElts = map.getLocalElementList();
1379 const GO minLhsGid = this->getMinGlobalIndex();
1380 const size_type numRhsElts = rhsElts.size();
1381 for (size_type k = 0; k < numRhsElts; ++k) {
1382 const GO curLhsGid = minLhsGid + static_cast<GO>(k);
1383 if (curLhsGid != rhsElts[k]) {
1384 return false; // stop on first mismatch
1385 }
1386 }
1387 return true;
1388 }
1389 } else if (map.isContiguous()) { // *this is not contiguous, but map is
1391 this->isContiguous() || !map.isContiguous(), std::logic_error,
1392 "Tpetra::Map::locallySameAs: BUG");
1393 ArrayView<const GO> lhsElts = this->getLocalElementList();
1394 const GO minRhsGid = map.getMinGlobalIndex();
1395 const size_type numLhsElts = lhsElts.size();
1396 for (size_type k = 0; k < numLhsElts; ++k) {
1397 const GO curRhsGid = minRhsGid + static_cast<GO>(k);
1398 if (curRhsGid != lhsElts[k]) {
1399 return false; // stop on first mismatch
1400 }
1401 }
1402 return true;
1403 } else if (this->lgMap_.data() == map.lgMap_.data()) {
1404 // Pointers to LID->GID "map" (actually just an array) are the
1405 // same, and the number of GIDs are the same.
1406 return this->getLocalNumElements() == map.getLocalNumElements();
1407 } else { // we actually have to compare the GIDs
1408 if (this->getLocalNumElements() != map.getLocalNumElements()) {
1409 return false; // We already checked above, but check just in case
1410 } else {
1411 using range_type = Kokkos::RangePolicy<LocalOrdinal, typename node_type::execution_space>;
1412
1413 auto lhsLclMap = getLocalMap();
1414 auto rhsLclMap = map.getLocalMap();
1415
1417 Kokkos::parallel_reduce(
1418 "Tpetra::Map::locallySameAs",
1419 range_type(0, this->getLocalNumElements()),
1421 if (lhsLclMap.getGlobalElement(lid) != rhsLclMap.getGlobalElement(lid))
1422 ++numMismatches;
1423 },
1425
1426 return (numMismatchedElements == 0);
1427 }
1428 }
1429 }
1430}
1431
1432template <class LocalOrdinal, class GlobalOrdinal, class Node>
1435 if (this == &map)
1436 return true;
1437
1438 // We are going to check if lmap1 is fitted into lmap2:
1439 // Is lmap1 (map) a subset of lmap2 (this)?
1440 // And do the first lmap1.getLocalNumElements() global elements
1441 // of lmap1,lmap2 owned on each process exactly match?
1442 auto lmap1 = map.getLocalMap();
1443 auto lmap2 = this->getLocalMap();
1444
1445 auto numLocalElements1 = lmap1.getLocalNumElements();
1446 auto numLocalElements2 = lmap2.getLocalNumElements();
1447
1449 // There are more indices in the first map on this process than in second map.
1450 return false;
1451 }
1452
1453 if (lmap1.isContiguous() && lmap2.isContiguous()) {
1454 // When both Maps are contiguous, just check the interval inclusion.
1455 return ((lmap1.getMinGlobalIndex() == lmap2.getMinGlobalIndex()) &&
1456 (lmap1.getMaxGlobalIndex() <= lmap2.getMaxGlobalIndex()));
1457 }
1458
1459 if (lmap1.getMinGlobalIndex() < lmap2.getMinGlobalIndex() ||
1460 lmap1.getMaxGlobalIndex() > lmap2.getMaxGlobalIndex()) {
1461 // The second map does not include the first map bounds, and thus some of
1462 // the first map global indices are not in the second map.
1463 return false;
1464 }
1465
1466 using LO = local_ordinal_type;
1467 using range_type =
1468 Kokkos::RangePolicy<LO, typename node_type::execution_space>;
1469
1470 // Check all elements.
1471 LO numDiff = 0;
1472 Kokkos::parallel_reduce(
1473 "isLocallyFitted",
1474 range_type(0, numLocalElements1),
1475 KOKKOS_LAMBDA(const LO i, LO& diff) {
1476 diff += (lmap1.getGlobalElement(i) != lmap2.getGlobalElement(i));
1477 },
1478 numDiff);
1479
1480 return (numDiff == 0);
1481}
1482
1483template <class LocalOrdinal, class GlobalOrdinal, class Node>
1486 using Teuchos::outArg;
1487 using Teuchos::REDUCE_MIN;
1488 using Teuchos::reduceAll;
1489 //
1490 // Tests that avoid the Boolean all-reduce below by using
1491 // globally consistent quantities.
1492 //
1493 if (this == &map) {
1494 // Pointer equality on one process always implies pointer
1495 // equality on all processes, since Map is immutable.
1496 return true;
1497 } else if (getComm()->getSize() != map.getComm()->getSize()) {
1498 // The two communicators have different numbers of processes.
1499 // It's not correct to call isSameAs() in that case. This
1500 // may result in the all-reduce hanging below.
1501 return false;
1502 } else if (getGlobalNumElements() != map.getGlobalNumElements()) {
1503 // Two Maps are definitely NOT the same if they have different
1504 // global numbers of indices.
1505 return false;
1506 } else if (haveGlobalConstants() && map.haveGlobalConstants() && (getMinAllGlobalIndex() != map.getMinAllGlobalIndex() || getMaxAllGlobalIndex() != map.getMaxAllGlobalIndex() || getIndexBase() != map.getIndexBase())) {
1507 // If the global min or max global index doesn't match, or if
1508 // the index base doesn't match, then the Maps aren't the same.
1509 return false;
1510 } else if (haveGlobalConstants() && map.haveGlobalConstants() && (isDistributed() != map.isDistributed())) {
1511 // One Map is distributed and the other is not, which means that
1512 // the Maps aren't the same.
1513 return false;
1514 } else if (isContiguous() && isUniform() &&
1515 map.isContiguous() && map.isUniform()) {
1516 // Contiguous uniform Maps with the same number of processes in
1517 // their communicators, with the same global numbers of indices,
1518 // and with matching index bases and ranges, must be the same.
1519 return true;
1520 }
1521
1522 // The two communicators must have the same number of processes,
1523 // with process ranks occurring in the same order. This uses
1524 // MPI_COMM_COMPARE. The MPI 3.1 standard (Section 6.4) says:
1525 // "Operations that access communicators are local and their
1526 // execution does not require interprocess communication."
1527 // However, just to be sure, I'll put this call after the above
1528 // tests that don't communicate.
1529 if (!::Tpetra::Details::congruent(*comm_, *(map.getComm()))) {
1530 return false;
1531 }
1532
1533 // If we get this far, we need to check local properties and then
1534 // communicate local sameness across all processes.
1535 const int isSame_lcl = locallySameAs(map) ? 1 : 0;
1536
1537 // Return true if and only if all processes report local sameness.
1538 int isSame_gbl = 0;
1540 return isSame_gbl == 1;
1541}
1542
1543namespace { // (anonymous)
1544template <class LO, class GO, class DT>
1545class FillLgMap {
1546 public:
1547 FillLgMap(const Kokkos::View<GO*, DT>& lgMap,
1548 const GO startGid)
1549 : lgMap_(lgMap)
1550 , startGid_(startGid) {
1551 Kokkos::RangePolicy<LO, typename DT::execution_space>
1552 range(static_cast<LO>(0), static_cast<LO>(lgMap.size()));
1553 Kokkos::parallel_for(range, *this);
1554 }
1555
1556 KOKKOS_INLINE_FUNCTION void operator()(const LO& lid) const {
1557 lgMap_(lid) = startGid_ + static_cast<GO>(lid);
1558 }
1559
1560 private:
1561 const Kokkos::View<GO*, DT> lgMap_;
1562 const GO startGid_;
1563};
1564
1565} // namespace
1566
1567template <class LocalOrdinal, class GlobalOrdinal, class Node>
1568typename Map<LocalOrdinal, GlobalOrdinal, Node>::global_indices_array_type
1570 using std::endl;
1571 using LO = local_ordinal_type;
1572 using GO = global_ordinal_type;
1573 using const_lg_view_type = decltype(lgMap_);
1574 using lg_view_type = typename const_lg_view_type::non_const_type;
1575 const bool debug = Details::Behavior::debug("Map");
1576 const bool verbose = Details::Behavior::verbose("Map");
1577
1578 std::unique_ptr<std::string> prefix;
1579 if (verbose) {
1581 comm_.getRawPtr(), "Map", "getMyGlobalIndices");
1582 std::ostringstream os;
1583 os << *prefix << "Start" << endl;
1584 std::cerr << os.str();
1585 }
1586
1587 // If the local-to-global mapping doesn't exist yet, and if we
1588 // have local entries, then create and fill the local-to-global
1589 // mapping.
1591 lgMap_.extent(0) == 0 && numLocalElements_ > 0;
1592
1594 if (verbose) {
1595 std::ostringstream os;
1596 os << *prefix << "Need to create lgMap" << endl;
1597 std::cerr << os.str();
1598 }
1599 if (debug) {
1600 // The local-to-global mapping should have been set up already
1601 // for a noncontiguous map.
1602 TEUCHOS_TEST_FOR_EXCEPTION(!isContiguous(), std::logic_error,
1603 "Tpetra::Map::getMyGlobalIndices: The local-to-global "
1604 "mapping (lgMap_) should have been set up already for a "
1605 "noncontiguous Map. Please report this bug to the Tpetra "
1606 "developers.");
1607 }
1608 const LO numElts = static_cast<LO>(getLocalNumElements());
1609
1610 using Kokkos::view_alloc;
1611 using Kokkos::WithoutInitializing;
1612 lg_view_type lgMap("lgMap3", numElts);
1613 if (verbose) {
1614 std::ostringstream os;
1615 os << *prefix << "Fill lgMap" << endl;
1616 std::cerr << os.str();
1617 }
1619
1620 if (verbose) {
1621 std::ostringstream os;
1622 os << *prefix << "Copy lgMap to lgMapHost" << endl;
1623 std::cerr << os.str();
1624 }
1625
1626 auto lgMapHost = Kokkos::create_mirror_view(Kokkos::HostSpace(), lgMap);
1627 // DEEP_COPY REVIEW - DEVICE-TO-HOST
1629 Kokkos::deep_copy(exec_instance, lgMapHost, lgMap);
1630
1631 // There's a non-trivial chance we'll grab this on the host,
1632 // so let's make sure the copy finishes
1633 exec_instance.fence();
1634
1635 // "Commit" the local-to-global lookup table we filled in above.
1636 lgMap_ = lgMap;
1637 lgMapHost_ = lgMapHost;
1638 } else {
1639 lazyPushToHost();
1640 }
1641
1642 if (verbose) {
1643 std::ostringstream os;
1644 os << *prefix << "Done" << endl;
1645 std::cerr << os.str();
1646 }
1647 return lgMapHost_;
1648}
1649
1650template <class LocalOrdinal, class GlobalOrdinal, class Node>
1651typename Map<LocalOrdinal, GlobalOrdinal, Node>::global_indices_array_device_type
1653 using std::endl;
1654 using LO = local_ordinal_type;
1655 using GO = global_ordinal_type;
1656 using const_lg_view_type = decltype(lgMap_);
1657 using lg_view_type = typename const_lg_view_type::non_const_type;
1658 const bool debug = Details::Behavior::debug("Map");
1659 const bool verbose = Details::Behavior::verbose("Map");
1660
1661 std::unique_ptr<std::string> prefix;
1662 if (verbose) {
1664 comm_.getRawPtr(), "Map", "getMyGlobalIndicesDevice");
1665 std::ostringstream os;
1666 os << *prefix << "Start" << endl;
1667 std::cerr << os.str();
1668 }
1669
1670 // If the local-to-global mapping doesn't exist yet, and if we
1671 // have local entries, then create and fill the local-to-global
1672 // mapping.
1674 lgMap_.extent(0) == 0 && numLocalElements_ > 0;
1675
1677 if (verbose) {
1678 std::ostringstream os;
1679 os << *prefix << "Need to create lgMap" << endl;
1680 std::cerr << os.str();
1681 }
1682 if (debug) {
1683 // The local-to-global mapping should have been set up already
1684 // for a noncontiguous map.
1685 TEUCHOS_TEST_FOR_EXCEPTION(!isContiguous(), std::logic_error,
1686 "Tpetra::Map::getMyGlobalIndices: The local-to-global "
1687 "mapping (lgMap_) should have been set up already for a "
1688 "noncontiguous Map. Please report this bug to the Tpetra "
1689 "developers.");
1690 }
1691 const LO numElts = static_cast<LO>(getLocalNumElements());
1692
1693 using Kokkos::view_alloc;
1694 using Kokkos::WithoutInitializing;
1695 lg_view_type lgMap("lgMap4", numElts);
1696 if (verbose) {
1697 std::ostringstream os;
1698 os << *prefix << "Fill lgMap" << endl;
1699 std::cerr << os.str();
1700 }
1702
1703 // "Commit" the local-to-global lookup table we filled in above.
1704 lgMap_ = lgMap;
1705 }
1706
1707 if (verbose) {
1708 std::ostringstream os;
1709 os << *prefix << "Done" << endl;
1710 std::cerr << os.str();
1711 }
1712 return lgMap_;
1713}
1714
1715template <class LocalOrdinal, class GlobalOrdinal, class Node>
1716Teuchos::ArrayView<const GlobalOrdinal>
1718 using GO = global_ordinal_type;
1719
1720 // If the local-to-global mapping doesn't exist yet, and if we
1721 // have local entries, then create and fill the local-to-global
1722 // mapping.
1723 (void)this->getMyGlobalIndices();
1724
1725 // This does NOT assume UVM; lgMapHost_ is a host pointer.
1726 lazyPushToHost();
1727 const GO* lgMapHostRawPtr = lgMapHost_.data();
1728 // The third argument forces ArrayView not to try to track memory
1729 // in a debug build. We have to use it because the memory does
1730 // not belong to a Teuchos memory management class.
1731 return Teuchos::ArrayView<const GO>(
1733 lgMapHost_.extent(0),
1734 Teuchos::RCP_DISABLE_NODE_LOOKUP);
1735}
1736
1737template <class LocalOrdinal, class GlobalOrdinal, class Node>
1739 return distributed_;
1740}
1741
1742template <class LocalOrdinal, class GlobalOrdinal, class Node>
1744 using Teuchos::TypeNameTraits;
1745 std::ostringstream os;
1746
1747 os << "Tpetra::Map: {"
1748 << "LocalOrdinalType: " << TypeNameTraits<LocalOrdinal>::name()
1749 << ", GlobalOrdinalType: " << TypeNameTraits<GlobalOrdinal>::name()
1750 << ", NodeType: " << TypeNameTraits<Node>::name();
1751 if (this->getObjectLabel() != "") {
1752 os << ", Label: \"" << this->getObjectLabel() << "\"";
1753 }
1754 os << ", Global number of entries: " << getGlobalNumElements()
1755 << ", Number of processes: " << getComm()->getSize()
1756 << ", Uniform: " << (isUniform() ? "true" : "false")
1757 << ", Contiguous: " << (isContiguous() ? "true" : "false")
1758 << ", Distributed: " << (isDistributed() ? "true" : "false")
1759 << "}";
1760 return os.str();
1761}
1762
1767template <class LocalOrdinal, class GlobalOrdinal, class Node>
1768std::string
1770 localDescribeToString(const Teuchos::EVerbosityLevel vl) const {
1771 using LO = local_ordinal_type;
1772 using std::endl;
1773
1774 // This preserves current behavior of Map.
1775 if (vl < Teuchos::VERB_HIGH) {
1776 return std::string();
1777 }
1778 auto outStringP = Teuchos::rcp(new std::ostringstream());
1779 Teuchos::RCP<Teuchos::FancyOStream> outp =
1780 Teuchos::getFancyOStream(outStringP);
1781 Teuchos::FancyOStream& out = *outp;
1782
1783 auto comm = this->getComm();
1784 const int myRank = comm->getRank();
1785 const int numProcs = comm->getSize();
1786 out << "Process " << myRank << " of " << numProcs << ":" << endl;
1787 Teuchos::OSTab tab1(out);
1788
1789 const LO numEnt = static_cast<LO>(this->getLocalNumElements());
1790 out << "My number of entries: " << numEnt << endl
1791 << "My minimum global index: " << this->getMinGlobalIndex() << endl
1792 << "My maximum global index: " << this->getMaxGlobalIndex() << endl;
1793
1794 if (vl == Teuchos::VERB_EXTREME) {
1795 out << "My global indices: [";
1796 const LO minLclInd = this->getMinLocalIndex();
1797 for (LO k = 0; k < numEnt; ++k) {
1798 out << minLclInd + this->getGlobalElement(k);
1799 if (k + 1 < numEnt) {
1800 out << ", ";
1801 }
1802 }
1803 out << "]" << endl;
1804 }
1805
1806 out.flush(); // make sure the ostringstream got everything
1807 return outStringP->str();
1808}
1809
1810template <class LocalOrdinal, class GlobalOrdinal, class Node>
1812 describe(Teuchos::FancyOStream& out,
1813 const Teuchos::EVerbosityLevel verbLevel) const {
1814 using std::endl;
1815 using Teuchos::TypeNameTraits;
1816 using Teuchos::VERB_DEFAULT;
1817 using Teuchos::VERB_HIGH;
1818 using Teuchos::VERB_LOW;
1819 using Teuchos::VERB_NONE;
1820 using LO = local_ordinal_type;
1821 using GO = global_ordinal_type;
1822 const Teuchos::EVerbosityLevel vl =
1824
1825 if (vl == VERB_NONE) {
1826 return; // don't print anything
1827 }
1828 // If this Map's Comm is null, then the Map does not participate
1829 // in collective operations with the other processes. In that
1830 // case, it is not even legal to call this method. The reasonable
1831 // thing to do in that case is nothing.
1832 auto comm = this->getComm();
1833 if (comm.is_null()) {
1834 return;
1835 }
1836 const int myRank = comm->getRank();
1837 const int numProcs = comm->getSize();
1838
1839 // Only Process 0 should touch the output stream, but this method
1840 // in general may need to do communication. Thus, we may need to
1841 // preserve the current tab level across multiple "if (myRank ==
1842 // 0) { ... }" inner scopes. This is why we sometimes create
1843 // OSTab instances by pointer, instead of by value. We only need
1844 // to create them by pointer if the tab level must persist through
1845 // multiple inner scopes.
1846 Teuchos::RCP<Teuchos::OSTab> tab0, tab1;
1847
1848 if (myRank == 0) {
1849 // At every verbosity level but VERB_NONE, Process 0 prints.
1850 // By convention, describe() always begins with a tab before
1851 // printing.
1852 tab0 = Teuchos::rcp(new Teuchos::OSTab(out));
1853 out << "\"Tpetra::Map\":" << endl;
1854 tab1 = Teuchos::rcp(new Teuchos::OSTab(out));
1855 {
1856 out << "Template parameters:" << endl;
1857 Teuchos::OSTab tab2(out);
1858 out << "LocalOrdinal: " << TypeNameTraits<LO>::name() << endl
1859 << "GlobalOrdinal: " << TypeNameTraits<GO>::name() << endl
1860 << "Node: " << TypeNameTraits<Node>::name() << endl;
1861 }
1862 const std::string label = this->getObjectLabel();
1863 if (label != "") {
1864 out << "Label: \"" << label << "\"" << endl;
1865 }
1866 out << "Global number of entries: " << getGlobalNumElements() << endl
1867 << "Minimum global index: " << getMinAllGlobalIndex() << endl
1868 << "Maximum global index: " << getMaxAllGlobalIndex() << endl
1869 << "Index base: " << getIndexBase() << endl
1870 << "Number of processes: " << numProcs << endl
1871 << "Uniform: " << (isUniform() ? "true" : "false") << endl
1872 << "Contiguous: " << (isContiguous() ? "true" : "false") << endl
1873 << "Distributed: " << (isDistributed() ? "true" : "false") << endl;
1874 }
1875
1876 // This is collective over the Map's communicator.
1877 if (vl >= VERB_HIGH) { // VERB_HIGH or VERB_EXTREME
1878 const std::string lclStr = this->localDescribeToString(vl);
1880 }
1881}
1882
1883template <class LocalOrdinal, class GlobalOrdinal, class Node>
1884Teuchos::RCP<const Map<LocalOrdinal, GlobalOrdinal, Node>>
1886 replaceCommWithSubset(const Teuchos::RCP<const Teuchos::Comm<int>>& newComm) const {
1887 using Teuchos::RCP;
1888 using Teuchos::rcp;
1889 using GST = global_size_t;
1890 using LO = local_ordinal_type;
1891 using GO = global_ordinal_type;
1892 using map_type = Map<LO, GO, Node>;
1893
1894 // mfh 26 Mar 2013: The lazy way to do this is simply to recreate
1895 // the Map by calling its ordinary public constructor, using the
1896 // original Map's data. This only involves O(1) all-reduces over
1897 // the new communicator, which in the common case only includes a
1898 // small number of processes.
1899
1900 // Create the Map to return.
1901 if (newComm.is_null() || newComm->getSize() < 1) {
1902 return Teuchos::null; // my process does not participate in the new Map
1903 } else if (newComm->getSize() == 1) {
1904 lazyPushToHost();
1905
1906 // The case where the new communicator has only one process is
1907 // easy. We don't have to communicate to get all the
1908 // information we need. Use the default comm to create the new
1909 // Map, then fill in all the fields directly.
1910 RCP<map_type> newMap(new map_type());
1911
1912 newMap->comm_ = newComm;
1913 // mfh 07 Oct 2016: Preserve original behavior, even though the
1914 // original index base may no longer be the globally min global
1915 // index. See #616 for why this doesn't matter so much anymore.
1916 newMap->indexBase_ = this->indexBase_;
1917 newMap->numGlobalElements_ = this->numLocalElements_;
1918 newMap->numLocalElements_ = this->numLocalElements_;
1919 newMap->minMyGID_ = this->minMyGID_;
1920 newMap->maxMyGID_ = this->maxMyGID_;
1921 newMap->minAllGID_ = this->minMyGID_;
1922 newMap->maxAllGID_ = this->maxMyGID_;
1923 newMap->firstContiguousGID_ = this->firstContiguousGID_;
1924 newMap->lastContiguousGID_ = this->lastContiguousGID_;
1925 newMap->haveGlobalConstants_ = this->haveGlobalConstants_;
1926 // Since the new communicator has only one process, neither
1927 // uniformity nor contiguity have changed.
1928 newMap->uniform_ = this->uniform_;
1929 newMap->contiguous_ = this->contiguous_;
1930 // The new communicator only has one process, so the new Map is
1931 // not distributed.
1932 newMap->distributed_ = false;
1933 newMap->lgMap_ = this->lgMap_;
1934 newMap->lgMapHost_ = this->lgMapHost_;
1935 newMap->glMap_ = this->glMap_;
1936 newMap->glMapHost_ = this->glMapHost_;
1937 // It's OK not to initialize the new Map's Directory.
1938 // This is initialized lazily, on first call to getRemoteIndexList.
1939
1940 return newMap;
1941 } else { // newComm->getSize() != 1
1942 // Even if the original Map is contiguous, the new Map might not
1943 // be, especially if the excluded processes have ranks != 0 or
1944 // newComm->getSize()-1. The common case for this method is to
1945 // exclude many (possibly even all but one) processes, so it
1946 // likely doesn't pay to do the global communication (over the
1947 // original communicator) to figure out whether we can optimize
1948 // the result Map. Thus, we just set up the result Map as
1949 // noncontiguous.
1950 //
1951 // TODO (mfh 07 Oct 2016) We don't actually need to reconstruct
1952 // the global-to-local table, etc. Optimize this code path to
1953 // avoid unnecessary local work.
1954
1955 // Make Map (re)compute the global number of elements.
1956 const GST RECOMPUTE = Tpetra::Details::OrdinalTraits<GST>::invalid();
1957 // TODO (mfh 07 Oct 2016) If we use any Map constructor, we have
1958 // to use the noncontiguous Map constructor, since the new Map
1959 // might not be contiguous. Even if the old Map was contiguous,
1960 // some process in the "middle" might have been excluded. If we
1961 // want to avoid local work, we either have to do the setup by
1962 // hand, or write a new Map constructor.
1963#if 1
1964 // The disabled code here throws the following exception in
1965 // Map's replaceCommWithSubset test:
1966 //
1967 // Throw test that evaluated to true: static_cast<unsigned long long> (numKeys) > static_cast<unsigned long long> (::Kokkos::ArithTraits<ValueType>::max ())
1968 // 10:
1969 // 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.
1970 // 10: Process 3: origComm->replaceCommWithSubset(subsetComm) threw an exception: /scratch/prj/Trilinos/Trilinos/packages/tpetra/core/src/Tpetra_Details_FixedHashTable_def.hpp:1044:
1971
1972 auto lgMap = this->getMyGlobalIndices();
1973 using size_type =
1974 typename std::decay<decltype(lgMap.extent(0))>::type;
1975 const size_type lclNumInds =
1976 static_cast<size_type>(this->getLocalNumElements());
1977 using Teuchos::TypeNameTraits;
1978 TEUCHOS_TEST_FOR_EXCEPTION(lgMap.extent(0) != lclNumInds, std::logic_error,
1979 "Tpetra::Map::replaceCommWithSubset: Result of getMyGlobalIndices() "
1980 "has length "
1981 << lgMap.extent(0) << " (of type " << TypeNameTraits<size_type>::name() << ") != this->getLocalNumElements()"
1982 " = "
1983 << this->getLocalNumElements() << ". The latter, upon being "
1984 "cast to size_type = "
1986 "becomes "
1987 << lclNumInds << ". Please report this bug to the Tpetra "
1988 "developers.");
1989#else
1990 Teuchos::ArrayView<const GO> lgMap = this->getLocalElementList();
1991#endif // 1
1992
1993 const GO indexBase = this->getIndexBase();
1994 // map stores HostSpace of CudaSpace but constructor is still CudaUVMSpace
1995 auto lgMap_device = Kokkos::create_mirror_view_and_copy(device_type(), lgMap);
1996 return rcp(new map_type(RECOMPUTE, lgMap_device, indexBase, newComm));
1997 }
1998}
1999
2000template <class LocalOrdinal, class GlobalOrdinal, class Node>
2001Teuchos::RCP<const Map<LocalOrdinal, GlobalOrdinal, Node>>
2003 removeEmptyProcesses() const {
2004 Tpetra::Details::ProfilingRegion pr("Map::removeEmptyProcesses");
2005 using Teuchos::Comm;
2006 using Teuchos::null;
2007 using Teuchos::outArg;
2008 using Teuchos::RCP;
2009 using Teuchos::rcp;
2010 using Teuchos::REDUCE_MIN;
2011 using Teuchos::reduceAll;
2012
2013 // Create the new communicator. split() returns a valid
2014 // communicator on all processes. On processes where color == 0,
2015 // ignore the result. Passing key == 0 tells MPI to order the
2016 // processes in the new communicator by their rank in the old
2017 // communicator.
2018 const int color = (numLocalElements_ == 0) ? 0 : 1;
2019 // MPI_Comm_split must be called collectively over the original
2020 // communicator. We can't just call it on processes with color
2021 // one, even though we will ignore its result on processes with
2022 // color zero.
2023 RCP<const Comm<int>> newComm = comm_->split(color, 0);
2024 if (color == 0) {
2025 newComm = null;
2026 }
2027
2028 // Create the Map to return.
2029 if (newComm.is_null()) {
2030 return null; // my process does not participate in the new Map
2031 } else {
2032 RCP<Map> map = rcp(new Map());
2033
2034 map->comm_ = newComm;
2035 map->indexBase_ = indexBase_;
2036 map->numGlobalElements_ = numGlobalElements_;
2037 map->numLocalElements_ = numLocalElements_;
2038 map->minMyGID_ = minMyGID_;
2039 map->maxMyGID_ = maxMyGID_;
2040 map->minAllGID_ = minAllGID_;
2041 map->maxAllGID_ = maxAllGID_;
2042 map->firstContiguousGID_ = firstContiguousGID_;
2043 map->lastContiguousGID_ = lastContiguousGID_;
2044 map->haveGlobalConstants_ = haveGlobalConstants_;
2045
2046 // Uniformity and contiguity have not changed. The directory
2047 // has changed, but we've taken care of that above.
2048 map->uniform_ = uniform_;
2049 map->contiguous_ = contiguous_;
2050
2051 // If the original Map was NOT distributed, then the new Map
2052 // cannot be distributed.
2053 //
2054 // If the number of processes in the new communicator is 1, then
2055 // the new Map is not distributed.
2056 //
2057 // Otherwise, we have to check the new Map using an all-reduce
2058 // (over the new communicator). For example, the original Map
2059 // may have had some processes with zero elements, and all other
2060 // processes with the same number of elements as in the whole
2061 // Map. That Map is technically distributed, because of the
2062 // processes with zero elements. Removing those processes would
2063 // make the new Map locally replicated.
2064 if (!distributed_ || newComm->getSize() == 1) {
2065 map->distributed_ = false;
2066 if (newComm->getSize() == 1) {
2067 map->minAllGID_ = map->minMyGID_;
2068 map->maxAllGID_ = map->maxMyGID_;
2069 map->haveGlobalConstants_ = true;
2070 }
2071 } else {
2072 const int iOwnAllGids = (numLocalElements_ == numGlobalElements_) ? 1 : 0;
2073 int allProcsOwnAllGids = 0;
2075 map->distributed_ = (allProcsOwnAllGids == 1) ? false : true;
2076 }
2077
2078 map->lgMap_ = lgMap_;
2079 map->lgMapHost_ = lgMapHost_;
2080 map->glMap_ = glMap_;
2081 map->glMapHost_ = glMapHost_;
2082
2083 // Map's default constructor creates an uninitialized Directory.
2084 // The Directory will be initialized on demand in
2085 // getRemoteIndexList().
2086 //
2087 // FIXME (mfh 26 Mar 2013) It should be possible to "filter" the
2088 // directory more efficiently than just recreating it. If
2089 // directory recreation proves a bottleneck, we can always
2090 // revisit this. On the other hand, Directory creation is only
2091 // collective over the new, presumably much smaller
2092 // communicator, so it may not be worth the effort to optimize.
2093
2094 return map;
2095 }
2096}
2097
2098template <class LocalOrdinal, class GlobalOrdinal, class Node>
2101 directory_.is_null(), std::logic_error,
2102 "Tpetra::Map::setupDirectory: "
2103 "The Directory is null. "
2104 "Please report this bug to the Tpetra developers.");
2105
2106 // Only create the Directory if it hasn't been created yet.
2107 // This is a collective operation.
2108 if (!directory_->initialized()) {
2109 // non-contiguous directory needs global constants
2110 if (isDistributed() && !isUniform() && !isContiguous())
2111 computeGlobalConstants();
2112 directory_->initialize(*this);
2113 }
2114}
2115
2116template <class LocalOrdinal, class GlobalOrdinal, class Node>
2119 getRemoteIndexList(const Teuchos::ArrayView<const GlobalOrdinal>& GIDs,
2120 const Teuchos::ArrayView<int>& PIDs,
2121 const Teuchos::ArrayView<LocalOrdinal>& LIDs) const {
2123 using std::endl;
2124 using Tpetra::Details::OrdinalTraits;
2125 using size_type = Teuchos::ArrayView<int>::size_type;
2126
2127 const bool verbose = Details::Behavior::verbose("Map");
2129 std::unique_ptr<std::string> prefix;
2130 if (verbose) {
2131 prefix = Details::createPrefix(comm_.getRawPtr(),
2132 "Map", "getRemoteIndexList(GIDs,PIDs,LIDs)");
2133 std::ostringstream os;
2134 os << *prefix << "Start: ";
2135 verbosePrintArray(os, GIDs, "GIDs", maxNumToPrint);
2136 os << endl;
2137 std::cerr << os.str();
2138 }
2139
2140 // Empty Maps (i.e., containing no indices on any processes in the
2141 // Map's communicator) are perfectly valid. In that case, if the
2142 // input GID list is nonempty, we fill the output arrays with
2143 // invalid values, and return IDNotPresent to notify the caller.
2144 // It's perfectly valid to give getRemoteIndexList GIDs that the
2145 // Map doesn't own. SubmapImport test 2 needs this functionality.
2146 if (getGlobalNumElements() == 0) {
2147 if (GIDs.size() == 0) {
2148 if (verbose) {
2149 std::ostringstream os;
2150 os << *prefix << "Done; both Map & input are empty" << endl;
2151 std::cerr << os.str();
2152 }
2153 return AllIDsPresent; // trivially
2154 } else {
2155 if (verbose) {
2156 std::ostringstream os;
2157 os << *prefix << "Done: Map is empty on all processes, "
2158 "so all output PIDs & LIDs are invalid (-1)."
2159 << endl;
2160 std::cerr << os.str();
2161 }
2162 for (size_type k = 0; k < PIDs.size(); ++k) {
2164 }
2165 for (size_type k = 0; k < LIDs.size(); ++k) {
2167 }
2168 return IDNotPresent;
2169 }
2170 }
2171
2172 // getRemoteIndexList must be called collectively, and Directory
2173 // initialization is collective too, so it's OK to initialize the
2174 // Directory on demand.
2175
2176 if (verbose) {
2177 std::ostringstream os;
2178 os << *prefix << "Call setupDirectory" << endl;
2179 std::cerr << os.str();
2180 }
2181 setupDirectory();
2182 if (verbose) {
2183 std::ostringstream os;
2184 os << *prefix << "Call directory_->getDirectoryEntries" << endl;
2185 std::cerr << os.str();
2186 }
2188 directory_->getDirectoryEntries(*this, GIDs, PIDs, LIDs);
2189 if (verbose) {
2190 std::ostringstream os;
2191 os << *prefix << "Done; getDirectoryEntries returned "
2192 << (retVal == IDNotPresent ? "IDNotPresent" : "AllIDsPresent")
2193 << "; ";
2194 verbosePrintArray(os, PIDs, "PIDs", maxNumToPrint);
2195 os << ", ";
2196 verbosePrintArray(os, LIDs, "LIDs", maxNumToPrint);
2197 os << endl;
2198 std::cerr << os.str();
2199 }
2200 return retVal;
2201}
2202
2203template <class LocalOrdinal, class GlobalOrdinal, class Node>
2206 getRemoteIndexList(const Teuchos::ArrayView<const GlobalOrdinal>& GIDs,
2207 const Teuchos::ArrayView<int>& PIDs) const {
2209 using std::endl;
2210
2211 const bool verbose = Details::Behavior::verbose("Map");
2213 std::unique_ptr<std::string> prefix;
2214 if (verbose) {
2215 prefix = Details::createPrefix(comm_.getRawPtr(),
2216 "Map", "getRemoteIndexList(GIDs,PIDs)");
2217 std::ostringstream os;
2218 os << *prefix << "Start: ";
2219 verbosePrintArray(os, GIDs, "GIDs", maxNumToPrint);
2220 os << endl;
2221 std::cerr << os.str();
2222 }
2223
2224 if (getGlobalNumElements() == 0) {
2225 if (GIDs.size() == 0) {
2226 if (verbose) {
2227 std::ostringstream os;
2228 os << *prefix << "Done; both Map & input are empty" << endl;
2229 std::cerr << os.str();
2230 }
2231 return AllIDsPresent; // trivially
2232 } else {
2233 if (verbose) {
2234 std::ostringstream os;
2235 os << *prefix << "Done: Map is empty on all processes, "
2236 "so all output PIDs are invalid (-1)."
2237 << endl;
2238 std::cerr << os.str();
2239 }
2240 for (Teuchos::ArrayView<int>::size_type k = 0; k < PIDs.size(); ++k) {
2241 PIDs[k] = Tpetra::Details::OrdinalTraits<int>::invalid();
2242 }
2243 return IDNotPresent;
2244 }
2245 }
2246
2247 // getRemoteIndexList must be called collectively, and Directory
2248 // initialization is collective too, so it's OK to initialize the
2249 // Directory on demand.
2250
2251 if (verbose) {
2252 std::ostringstream os;
2253 os << *prefix << "Call setupDirectory" << endl;
2254 std::cerr << os.str();
2255 }
2256 setupDirectory();
2257 if (verbose) {
2258 std::ostringstream os;
2259 os << *prefix << "Call directory_->getDirectoryEntries" << endl;
2260 std::cerr << os.str();
2261 }
2263 directory_->getDirectoryEntries(*this, GIDs, PIDs);
2264 if (verbose) {
2265 std::ostringstream os;
2266 os << *prefix << "Done; getDirectoryEntries returned "
2267 << (retVal == IDNotPresent ? "IDNotPresent" : "AllIDsPresent")
2268 << "; ";
2269 verbosePrintArray(os, PIDs, "PIDs", maxNumToPrint);
2270 os << endl;
2271 std::cerr << os.str();
2272 }
2273 return retVal;
2274}
2275
2276template <class LocalOrdinal, class GlobalOrdinal, class Node>
2278 using exec_space = typename Node::device_type::execution_space;
2279 if (lgMap_.extent(0) != lgMapHost_.extent(0)) {
2280 Tpetra::Details::ProfilingRegion pr("Map::lazyPushToHost() - pushing data");
2281 // NOTE: We check lgMap_ and not glMap_, since the latter can
2282 // be somewhat error prone for contiguous maps
2283
2284 // create_mirror_view preserves const-ness. create_mirror does not
2285 auto lgMap_host = Kokkos::create_mirror(Kokkos::HostSpace(), lgMap_);
2286
2287 // Since this was computed on the default stream, we can copy on the stream and then fence
2288 // the stream
2289 Kokkos::deep_copy(exec_space(), lgMap_host, lgMap_);
2290 exec_space().fence();
2291 lgMapHost_ = lgMap_host;
2292
2293 // Make host version - when memory spaces match these just do trivial assignment
2294 glMapHost_ = global_to_local_table_host_type(glMap_);
2295 }
2296}
2297
2298template <class LocalOrdinal, class GlobalOrdinal, class Node>
2299Teuchos::RCP<const Teuchos::Comm<int>>
2301 return comm_;
2302}
2303
2304template <class LocalOrdinal, class GlobalOrdinal, class Node>
2306 checkIsDist() const {
2307 using std::endl;
2308 using Teuchos::as;
2309 using Teuchos::outArg;
2310 using Teuchos::REDUCE_MIN;
2311 using Teuchos::reduceAll;
2312
2313 const bool verbose = Details::Behavior::verbose("Map");
2314 std::unique_ptr<std::string> prefix;
2315 if (verbose) {
2317 comm_.getRawPtr(), "Map", "checkIsDist");
2318 std::ostringstream os;
2319 os << *prefix << "Start" << endl;
2320 std::cerr << os.str();
2321 }
2322
2323 bool global = false;
2324 if (comm_->getSize() > 1) {
2325 // The communicator has more than one process, but that doesn't
2326 // necessarily mean the Map is distributed.
2327 int localRep = 0;
2328 if (numGlobalElements_ == as<global_size_t>(numLocalElements_)) {
2329 // The number of local elements on this process equals the
2330 // number of global elements.
2331 //
2332 // NOTE (mfh 22 Nov 2011) Does this still work if there were
2333 // duplicates in the global ID list on input (the third Map
2334 // constructor), so that the number of local elements (which
2335 // are not duplicated) on this process could be less than the
2336 // number of global elements, even if this process owns all
2337 // the elements?
2338 localRep = 1;
2339 }
2340 int allLocalRep;
2341 reduceAll<int, int>(*comm_, REDUCE_MIN, localRep, outArg(allLocalRep));
2342 if (allLocalRep != 1) {
2343 // At least one process does not own all the elements.
2344 // This makes the Map a distributed Map.
2345 global = true;
2346 }
2347 }
2348 // If the communicator has only one process, then the Map is not
2349 // distributed.
2350
2351 if (verbose) {
2352 std::ostringstream os;
2353 os << *prefix << "Done; global=" << (global ? "true" : "false")
2354 << endl;
2355 std::cerr << os.str();
2356 }
2357 return global;
2358}
2359
2360} // namespace Tpetra
2361
2362template <class LocalOrdinal, class GlobalOrdinal>
2363Teuchos::RCP<const Tpetra::Map<LocalOrdinal, GlobalOrdinal>>
2364Tpetra::createLocalMap(const size_t numElements,
2365 const Teuchos::RCP<const Teuchos::Comm<int>>& comm) {
2366 typedef LocalOrdinal LO;
2367 typedef GlobalOrdinal GO;
2368 using NT = typename ::Tpetra::Map<LO, GO>::node_type;
2369 return createLocalMapWithNode<LO, GO, NT>(numElements, comm);
2370}
2371
2372template <class LocalOrdinal, class GlobalOrdinal>
2373Teuchos::RCP<const Tpetra::Map<LocalOrdinal, GlobalOrdinal>>
2374Tpetra::createUniformContigMap(const global_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 createUniformContigMapWithNode<LO, GO, NT>(numElements, comm);
2380}
2381
2382template <class LocalOrdinal, class GlobalOrdinal, class Node>
2383Teuchos::RCP<const Tpetra::Map<LocalOrdinal, GlobalOrdinal, Node>>
2384Tpetra::createUniformContigMapWithNode(const global_size_t numElements,
2385 const Teuchos::RCP<const Teuchos::Comm<int>>& comm) {
2386 using Teuchos::rcp;
2388 const GlobalOrdinal indexBase = static_cast<GlobalOrdinal>(0);
2389
2390 return rcp(new map_type(numElements, indexBase, comm, GloballyDistributed));
2391}
2392
2393template <class LocalOrdinal, class GlobalOrdinal, class Node>
2394Teuchos::RCP<const Tpetra::Map<LocalOrdinal, GlobalOrdinal, Node>>
2395Tpetra::createLocalMapWithNode(const size_t numElements,
2396 const Teuchos::RCP<const Teuchos::Comm<int>>& comm) {
2397 using Teuchos::rcp;
2400 const GlobalOrdinal indexBase = 0;
2401 const global_size_t globalNumElts = static_cast<global_size_t>(numElements);
2402
2403 return rcp(new map_type(globalNumElts, indexBase, comm, LocallyReplicated));
2404}
2405
2406template <class LocalOrdinal, class GlobalOrdinal, class Node>
2407Teuchos::RCP<const Tpetra::Map<LocalOrdinal, GlobalOrdinal, Node>>
2409 const size_t localNumElements,
2410 const Teuchos::RCP<const Teuchos::Comm<int>>& comm) {
2411 using Teuchos::rcp;
2413 const GlobalOrdinal indexBase = 0;
2414
2415 return rcp(new map_type(numElements, localNumElements, indexBase, comm));
2416}
2417
2418template <class LocalOrdinal, class GlobalOrdinal>
2419Teuchos::RCP<const Tpetra::Map<LocalOrdinal, GlobalOrdinal>>
2421 const size_t localNumElements,
2422 const Teuchos::RCP<const Teuchos::Comm<int>>& comm) {
2423 typedef LocalOrdinal LO;
2424 typedef GlobalOrdinal GO;
2425 using NT = typename Tpetra::Map<LO, GO>::node_type;
2426
2427 return Tpetra::createContigMapWithNode<LO, GO, NT>(numElements, localNumElements, comm);
2428}
2429
2430template <class LocalOrdinal, class GlobalOrdinal>
2431Teuchos::RCP<const Tpetra::Map<LocalOrdinal, GlobalOrdinal>>
2432Tpetra::createNonContigMap(const Teuchos::ArrayView<const GlobalOrdinal>& elementList,
2433 const Teuchos::RCP<const Teuchos::Comm<int>>& comm) {
2434 typedef LocalOrdinal LO;
2435 typedef GlobalOrdinal GO;
2436 using NT = typename Tpetra::Map<LO, GO>::node_type;
2437
2438 return Tpetra::createNonContigMapWithNode<LO, GO, NT>(elementList, comm);
2439}
2440
2441template <class LocalOrdinal, class GlobalOrdinal, class Node>
2442Teuchos::RCP<const Tpetra::Map<LocalOrdinal, GlobalOrdinal, Node>>
2443Tpetra::createNonContigMapWithNode(const Teuchos::ArrayView<const GlobalOrdinal>& elementList,
2444 const Teuchos::RCP<const Teuchos::Comm<int>>& comm) {
2445 using Teuchos::rcp;
2447 using GST = Tpetra::global_size_t;
2448 const GST INV = Tpetra::Details::OrdinalTraits<GST>::invalid();
2449 // FIXME (mfh 22 Jul 2016) This is what I found here, but maybe this
2450 // shouldn't be zero, given that the index base is supposed to equal
2451 // the globally min global index?
2452 const GlobalOrdinal indexBase = 0;
2453
2454 return rcp(new map_type(INV, elementList, indexBase, comm));
2455}
2456
2457template <class LO, class GO, class NT>
2458Teuchos::RCP<const Tpetra::Map<LO, GO, NT>>
2459Tpetra::createOneToOne(const Teuchos::RCP<const Tpetra::Map<LO, GO, NT>>& M) {
2460 using Details::verbosePrintArray;
2461 using std::cerr;
2462 using std::endl;
2463 using Teuchos::Array;
2464 using Teuchos::ArrayView;
2465 using Teuchos::as;
2466 using Teuchos::rcp;
2467 using map_type = Tpetra::Map<LO, GO, NT>;
2468 using GST = global_size_t;
2469
2470 const bool verbose = Details::Behavior::verbose("Map");
2471 std::unique_ptr<std::string> prefix;
2472 if (verbose) {
2473 auto comm = M.is_null() ? Teuchos::null : M->getComm();
2474 prefix = Details::createPrefix(
2475 comm.getRawPtr(), "createOneToOne(Map)");
2476 std::ostringstream os;
2477 os << *prefix << "Start" << endl;
2478 cerr << os.str();
2479 }
2480 const size_t maxNumToPrint = verbose ? Details::Behavior::verbosePrintCountThreshold() : size_t(0);
2481 const GST GINV = Tpetra::Details::OrdinalTraits<GST>::invalid();
2482 const int myRank = M->getComm()->getRank();
2483
2484 // Bypasses for special cases where either M is known to be
2485 // one-to-one, or the one-to-one version of M is easy to compute.
2486 // This is why we take M as an RCP, not as a const reference -- so
2487 // that we can return M itself if it is 1-to-1.
2488 if (!M->isDistributed()) {
2489 // For a locally replicated Map, we assume that users want to push
2490 // all the GIDs to Process 0.
2491
2492 // mfh 05 Nov 2013: getGlobalNumElements() does indeed return what
2493 // you think it should return, in this special case of a locally
2494 // replicated contiguous Map.
2495 const GST numGlobalEntries = M->getGlobalNumElements();
2496 if (M->isContiguous()) {
2497 const size_t numLocalEntries =
2498 (myRank == 0) ? as<size_t>(numGlobalEntries) : size_t(0);
2499 if (verbose) {
2500 std::ostringstream os;
2501 os << *prefix << "Input is locally replicated & contiguous; "
2502 "numLocalEntries="
2503 << numLocalEntries << endl;
2504 cerr << os.str();
2505 }
2506 auto retMap =
2507 rcp(new map_type(numGlobalEntries, numLocalEntries,
2508 M->getIndexBase(), M->getComm()));
2509 if (verbose) {
2510 std::ostringstream os;
2511 os << *prefix << "Done" << endl;
2512 cerr << os.str();
2513 }
2514 return retMap;
2515 } else {
2516 if (verbose) {
2517 std::ostringstream os;
2518 os << *prefix << "Input is locally replicated & noncontiguous"
2519 << endl;
2520 cerr << os.str();
2521 }
2522 ArrayView<const GO> myGids =
2523 (myRank == 0) ? M->getLocalElementList() : Teuchos::null;
2524 auto retMap =
2525 rcp(new map_type(GINV, myGids(), M->getIndexBase(),
2526 M->getComm()));
2527 if (verbose) {
2528 std::ostringstream os;
2529 os << *prefix << "Done" << endl;
2530 cerr << os.str();
2531 }
2532 return retMap;
2533 }
2534 } else if (M->isContiguous()) {
2535 if (verbose) {
2536 std::ostringstream os;
2537 os << *prefix << "Input is distributed & contiguous" << endl;
2538 cerr << os.str();
2539 }
2540 // Contiguous, distributed Maps are one-to-one by construction.
2541 // (Locally replicated Maps can be contiguous.)
2542 return M;
2543 } else {
2544 if (verbose) {
2545 std::ostringstream os;
2546 os << *prefix << "Input is distributed & noncontiguous" << endl;
2547 cerr << os.str();
2548 }
2550 const size_t numMyElems = M->getLocalNumElements();
2551 ArrayView<const GO> myElems = M->getLocalElementList();
2552 Array<int> owner_procs_vec(numMyElems);
2553
2554 if (verbose) {
2555 std::ostringstream os;
2556 os << *prefix << "Call Directory::getDirectoryEntries: ";
2557 verbosePrintArray(os, myElems, "GIDs", maxNumToPrint);
2558 os << endl;
2559 cerr << os.str();
2560 }
2561 directory.getDirectoryEntries(*M, myElems, owner_procs_vec());
2562 if (verbose) {
2563 std::ostringstream os;
2564 os << *prefix << "getDirectoryEntries result: ";
2565 verbosePrintArray(os, owner_procs_vec, "PIDs", maxNumToPrint);
2566 os << endl;
2567 cerr << os.str();
2568 }
2569
2570 Array<GO> myOwned_vec(numMyElems);
2571 size_t numMyOwnedElems = 0;
2572 for (size_t i = 0; i < numMyElems; ++i) {
2573 const GO GID = myElems[i];
2574 const int owner = owner_procs_vec[i];
2575
2576 if (myRank == owner) {
2577 myOwned_vec[numMyOwnedElems++] = GID;
2578 }
2579 }
2580 myOwned_vec.resize(numMyOwnedElems);
2581
2582 if (verbose) {
2583 std::ostringstream os;
2584 os << *prefix << "Create Map: ";
2585 verbosePrintArray(os, myOwned_vec, "GIDs", maxNumToPrint);
2586 os << endl;
2587 cerr << os.str();
2588 }
2589 auto retMap = rcp(new map_type(GINV, myOwned_vec(),
2590 M->getIndexBase(), M->getComm()));
2591 if (verbose) {
2592 std::ostringstream os;
2593 os << *prefix << "Done" << endl;
2594 cerr << os.str();
2595 }
2596 return retMap;
2597 }
2598}
2599
2600template <class LocalOrdinal, class GlobalOrdinal, class Node>
2601Teuchos::RCP<const Tpetra::Map<LocalOrdinal, GlobalOrdinal, Node>>
2604 using Details::Behavior;
2605 using Details::verbosePrintArray;
2606 using std::cerr;
2607 using std::endl;
2608 using Teuchos::Array;
2609 using Teuchos::ArrayView;
2610 using Teuchos::RCP;
2611 using Teuchos::rcp;
2612 using Teuchos::toString;
2613 using LO = LocalOrdinal;
2614 using GO = GlobalOrdinal;
2615 using map_type = Tpetra::Map<LO, GO, Node>;
2616
2617 const bool verbose = Behavior::verbose("Map");
2618 std::unique_ptr<std::string> prefix;
2619 if (verbose) {
2620 auto comm = M.is_null() ? Teuchos::null : M->getComm();
2621 prefix = Details::createPrefix(
2622 comm.getRawPtr(), "createOneToOne(Map,TieBreak)");
2623 std::ostringstream os;
2624 os << *prefix << "Start" << endl;
2625 cerr << os.str();
2626 }
2627 const size_t maxNumToPrint = verbose ? Behavior::verbosePrintCountThreshold() : size_t(0);
2628
2629 // FIXME (mfh 20 Feb 2013) We should have a bypass for contiguous
2630 // Maps (which are 1-to-1 by construction).
2631
2633 if (verbose) {
2634 std::ostringstream os;
2635 os << *prefix << "Initialize Directory" << endl;
2636 cerr << os.str();
2637 }
2638 directory.initialize(*M, tie_break);
2639 if (verbose) {
2640 std::ostringstream os;
2641 os << *prefix << "Done initializing Directory" << endl;
2642 cerr << os.str();
2643 }
2644 size_t numMyElems = M->getLocalNumElements();
2645 ArrayView<const GO> myElems = M->getLocalElementList();
2646 Array<int> owner_procs_vec(numMyElems);
2647 if (verbose) {
2648 std::ostringstream os;
2649 os << *prefix << "Call Directory::getDirectoryEntries: ";
2650 verbosePrintArray(os, myElems, "GIDs", maxNumToPrint);
2651 os << endl;
2652 cerr << os.str();
2653 }
2654 directory.getDirectoryEntries(*M, myElems, owner_procs_vec());
2655 if (verbose) {
2656 std::ostringstream os;
2657 os << *prefix << "getDirectoryEntries result: ";
2658 verbosePrintArray(os, owner_procs_vec, "PIDs", maxNumToPrint);
2659 os << endl;
2660 cerr << os.str();
2661 }
2662
2663 const int myRank = M->getComm()->getRank();
2664 Array<GO> myOwned_vec(numMyElems);
2665 size_t numMyOwnedElems = 0;
2666 for (size_t i = 0; i < numMyElems; ++i) {
2667 const GO GID = myElems[i];
2668 const int owner = owner_procs_vec[i];
2669 if (myRank == owner) {
2670 myOwned_vec[numMyOwnedElems++] = GID;
2671 }
2672 }
2673 myOwned_vec.resize(numMyOwnedElems);
2674
2675 // FIXME (mfh 08 May 2014) The above Directory should be perfectly
2676 // valid for the new Map. Why can't we reuse it?
2677 const global_size_t GINV =
2678 Tpetra::Details::OrdinalTraits<global_size_t>::invalid();
2679 if (verbose) {
2680 std::ostringstream os;
2681 os << *prefix << "Create Map: ";
2682 verbosePrintArray(os, myOwned_vec, "GIDs", maxNumToPrint);
2683 os << endl;
2684 cerr << os.str();
2685 }
2686 RCP<const map_type> retMap(new map_type(GINV, myOwned_vec(), M->getIndexBase(),
2687 M->getComm()));
2688 if (verbose) {
2689 std::ostringstream os;
2690 os << *prefix << "Done" << endl;
2691 cerr << os.str();
2692 }
2693 return retMap;
2694}
2695
2696namespace Tpetra::Details {
2697
2698template <class pids_view_type>
2699struct SortToFit {
2700 int myRank;
2701 pids_view_type pids;
2702
2703 SortToFit(int _myRank, pids_view_type _pids)
2704 : myRank(_myRank)
2705 , pids(_pids) {}
2706
2707 KOKKOS_FUNCTION
2708 bool operator()(size_t i, size_t j) const {
2709 if (pids(i) == myRank) {
2710 if (pids(j) == myRank)
2711 return i < j;
2712 else
2713 return true;
2714 } else {
2715 if (pids(j) == myRank)
2716 return false;
2717 else
2718 return i < j;
2719 }
2720 }
2721};
2722
2723} // namespace Tpetra::Details
2724
2725template <class LO, class GO, class NT>
2726Teuchos::RCP<const Tpetra::Map<LO, GO, NT>>
2728 Teuchos::RCP<const Tpetra::Map<LO, GO, NT>> constM = M;
2730
2731 const int locallyFitted = M->isLocallyFitted(*owned_node_map);
2732 int globallyLocallyFitted = 0;
2733 reduceAll(*M->getComm(), Teuchos::REDUCE_MIN, locallyFitted, Teuchos::outArg(globallyLocallyFitted));
2734
2735 if (globallyLocallyFitted == 0) {
2736 using pid_type = int;
2737
2738 const pid_type myRank = M->getComm()->getRank();
2739 const size_t numMyElems = M->getLocalNumElements();
2740
2741 Kokkos::View<pid_type*, typename NT::memory_space> pids("pids", numMyElems);
2742 {
2743 auto gids_vec = M->getLocalElementList();
2744 Teuchos::Array<pid_type> pids_vec(numMyElems);
2745 M->getRemoteIndexList(gids_vec, pids_vec);
2746 Kokkos::View<pid_type*, Kokkos::HostSpace, Kokkos::MemoryTraits<Kokkos::Unmanaged>> pids_h(pids_vec.data(), pids_vec.size());
2747 Kokkos::deep_copy(pids, pids_h);
2748 }
2749
2750 auto gids = M->getMyGlobalIndicesDevice();
2751
2752 auto policy = Kokkos::RangePolicy<size_t, typename NT::execution_space>(0, numMyElems);
2753
2754 Kokkos::View<size_t*, typename NT::memory_space> idx(Kokkos::ViewAllocateWithoutInitializing("idx"), numMyElems);
2755 Kokkos::parallel_for(
2756 policy, KOKKOS_LAMBDA(const size_t i) { idx(i) = i; });
2757
2758 Tpetra::Details::SortToFit cmp(myRank, pids);
2759 Kokkos::sort(typename NT::execution_space(), idx, cmp);
2760
2761 Kokkos::View<GO*, typename NT::memory_space> new_gids(Kokkos::ViewAllocateWithoutInitializing("new_gids"), numMyElems);
2762 Kokkos::parallel_for(
2763 policy, KOKKOS_LAMBDA(const size_t i) { new_gids(i) = gids(idx(i)); });
2764
2765 Teuchos::RCP<const Tpetra::Map<LO, GO, NT>> shared_node_map =
2766 Teuchos::rcp(new Tpetra::Map<LO, GO, NT>(M->getGlobalNumElements(),
2767 new_gids,
2768 M->getIndexBase(),
2769 M->getComm()));
2770 M.swap(shared_node_map);
2771 }
2772
2773 return owned_node_map;
2774}
2775
2776//
2777// Explicit instantiation macro
2778//
2779// Must be expanded from within the Tpetra namespace!
2780//
2781
2783
2784#define TPETRA_MAP_INSTANT(LO, GO, NODE) \
2785 \
2786 template class Map<LO, GO, NODE>; \
2787 \
2788 template Teuchos::RCP<const Map<LO, GO, NODE>> \
2789 createLocalMapWithNode<LO, GO, NODE>(const size_t numElements, \
2790 const Teuchos::RCP<const Teuchos::Comm<int>>& comm); \
2791 \
2792 template Teuchos::RCP<const Map<LO, GO, NODE>> \
2793 createContigMapWithNode<LO, GO, NODE>(const global_size_t numElements, \
2794 const size_t localNumElements, \
2795 const Teuchos::RCP<const Teuchos::Comm<int>>& comm); \
2796 \
2797 template Teuchos::RCP<const Map<LO, GO, NODE>> \
2798 createNonContigMapWithNode(const Teuchos::ArrayView<const GO>& elementList, \
2799 const Teuchos::RCP<const Teuchos::Comm<int>>& comm); \
2800 \
2801 template Teuchos::RCP<const Map<LO, GO, NODE>> \
2802 createUniformContigMapWithNode<LO, GO, NODE>(const global_size_t numElements, \
2803 const Teuchos::RCP<const Teuchos::Comm<int>>& comm); \
2804 \
2805 template Teuchos::RCP<const Map<LO, GO, NODE>> \
2806 createOneToOne(const Teuchos::RCP<const Map<LO, GO, NODE>>& M); \
2807 \
2808 template Teuchos::RCP<const Map<LO, GO, NODE>> \
2809 createOneToOne(const Teuchos::RCP<const Map<LO, GO, NODE>>& M, \
2810 const Tpetra::Details::TieBreak<LO, GO>& tie_break); \
2811 \
2812 template Teuchos::RCP<const Map<LO, GO, NODE>> \
2813 createOneToOneAndMakeOverlappingMapFitted(Teuchos::RCP<const Map<LO, GO, NODE>>& M);
2814
2816#define TPETRA_MAP_INSTANT_DEFAULTNODE(LO, GO) \
2817 template Teuchos::RCP<const Map<LO, GO>> \
2818 createLocalMap<LO, GO>(const size_t, const Teuchos::RCP<const Teuchos::Comm<int>>&); \
2819 \
2820 template Teuchos::RCP<const Map<LO, GO>> \
2821 createContigMap<LO, GO>(global_size_t, size_t, \
2822 const Teuchos::RCP<const Teuchos::Comm<int>>&); \
2823 \
2824 template Teuchos::RCP<const Map<LO, GO>> \
2825 createNonContigMap(const Teuchos::ArrayView<const GO>&, \
2826 const Teuchos::RCP<const Teuchos::Comm<int>>&); \
2827 \
2828 template Teuchos::RCP<const Map<LO, GO>> \
2829 createUniformContigMap<LO, GO>(const global_size_t, \
2830 const Teuchos::RCP<const Teuchos::Comm<int>>&);
2831
2832#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.
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...