Tpetra parallel linear algebra  Version of the Day
Tpetra_Map_def.hpp
Go to the documentation of this file.
1 // @HEADER
2 // ***********************************************************************
3 //
4 // Tpetra: Templated Linear Algebra Services Package
5 // Copyright (2008) Sandia Corporation
6 //
7 // Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
8 // the U.S. Government retains certain rights in this software.
9 //
10 // Redistribution and use in source and binary forms, with or without
11 // modification, are permitted provided that the following conditions are
12 // met:
13 //
14 // 1. Redistributions of source code must retain the above copyright
15 // notice, this list of conditions and the following disclaimer.
16 //
17 // 2. Redistributions in binary form must reproduce the above copyright
18 // notice, this list of conditions and the following disclaimer in the
19 // documentation and/or other materials provided with the distribution.
20 //
21 // 3. Neither the name of the Corporation nor the names of the
22 // contributors may be used to endorse or promote products derived from
23 // this software without specific prior written permission.
24 //
25 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
26 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
29 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
30 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
31 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
32 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
33 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
34 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
35 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 //
37 // Questions? Contact Michael A. Heroux (maherou@sandia.gov)
38 //
39 // ************************************************************************
40 // @HEADER
41 
46 
47 #ifndef TPETRA_MAP_DEF_HPP
48 #define TPETRA_MAP_DEF_HPP
49 
50 #include "Tpetra_Directory.hpp" // must include for implicit instantiation to work
53 #include "Tpetra_Details_FixedHashTable.hpp"
54 #include "Tpetra_Details_gathervPrint.hpp"
56 #include "Tpetra_Core.hpp"
57 #include "Tpetra_Util.hpp"
58 #include "Teuchos_as.hpp"
59 #include "Teuchos_TypeNameTraits.hpp"
60 #include "Teuchos_CommHelpers.hpp"
61 #include "Tpetra_Details_mpiIsInitialized.hpp"
62 #include "Tpetra_Details_extractMpiCommFromTeuchos.hpp" // teuchosCommIsAnMpiComm
64 #include <memory>
65 #include <sstream>
66 #include <stdexcept>
67 #include <typeinfo>
68 
69 namespace { // (anonymous)
70 
71  template<class ExecutionSpace>
72  void
73  checkMapInputArray (const char ctorName[],
74  const void* indexList,
75  const size_t indexListSize,
76  const ExecutionSpace& execSpace,
77  const Teuchos::Comm<int>* const comm)
78  {
79  const bool debug = ::Tpetra::Details::Behavior::debug ();
80  if (debug) {
82  using Teuchos::outArg;
83  using Teuchos::REDUCE_MIN;
84  using Teuchos::reduceAll;
85  using std::endl;
86 
87  const int myRank = comm == nullptr ? 0 : comm->getRank ();
88  const bool verbose = ::Tpetra::Details::Behavior::verbose ();
89  std::ostringstream lclErrStrm;
90  int lclSuccess = 1;
91 
92  if (indexListSize != 0 && indexList == nullptr) {
93  lclSuccess = 0;
94  if (verbose) {
95  lclErrStrm << "Proc " << myRank << ": indexList is null, "
96  "but indexListSize=" << indexListSize << " != 0." << endl;
97  }
98  }
99  else {
100  if (indexListSize != 0 && indexList != nullptr &&
101  ! pointerAccessibleFromExecutionSpace (indexList, execSpace)) {
102  lclSuccess = 0;
103  if (verbose) {
104  using ::Tpetra::Details::memorySpaceName;
105  const std::string memSpaceName = memorySpaceName (indexList);
106  const std::string execSpaceName =
107  Teuchos::TypeNameTraits<ExecutionSpace>::name ();
108  lclErrStrm << "Proc " << myRank << ": Input array is not "
109  "accessible from the required execution space " <<
110  execSpaceName << ". As far as I can tell, array lives "
111  "in memory space " << memSpaceName << "." << endl;
112  }
113  }
114  }
115  int gblSuccess = 0; // output argument
116  reduceAll (*comm, REDUCE_MIN, lclSuccess, outArg (gblSuccess));
117  if (gblSuccess != 1) {
118  std::ostringstream gblErrStrm;
119  gblErrStrm << "Tpetra::Map constructor " << ctorName <<
120  " detected a problem with the input array "
121  "(raw array, Teuchos::ArrayView, or Kokkos::View) "
122  "of global indices." << endl;
123  if (verbose) {
124  using ::Tpetra::Details::gathervPrint;
125  gathervPrint (gblErrStrm, lclErrStrm.str (), *comm);
126  }
127  TEUCHOS_TEST_FOR_EXCEPTION
128  (true, std::invalid_argument, gblErrStrm.str ());
129  }
130  }
131  }
132 } // namespace (anonymous)
133 
134 namespace Tpetra {
135 
136  template <class LocalOrdinal, class GlobalOrdinal, class Node>
138  Map () :
139  comm_ (new Teuchos::SerialComm<int> ()),
140  indexBase_ (0),
141  numGlobalElements_ (0),
142  numLocalElements_ (0),
143  minMyGID_ (Tpetra::Details::OrdinalTraits<GlobalOrdinal>::invalid ()),
144  maxMyGID_ (Tpetra::Details::OrdinalTraits<GlobalOrdinal>::invalid ()),
145  minAllGID_ (Tpetra::Details::OrdinalTraits<GlobalOrdinal>::invalid ()),
146  maxAllGID_ (Tpetra::Details::OrdinalTraits<GlobalOrdinal>::invalid ()),
147  firstContiguousGID_ (Tpetra::Details::OrdinalTraits<GlobalOrdinal>::invalid ()),
148  lastContiguousGID_ (Tpetra::Details::OrdinalTraits<GlobalOrdinal>::invalid ()),
149  uniform_ (false), // trivially
150  contiguous_ (false),
151  distributed_ (false), // no communicator yet
152  directory_ (new Directory<LocalOrdinal, GlobalOrdinal, Node> ())
153  {
155  }
156 
157 #ifdef TPETRA_ENABLE_DEPRECATED_CODE
158  template <class LocalOrdinal, class GlobalOrdinal, class Node>
159  TPETRA_DEPRECATED
161  Map (const global_size_t numGlobalElements,
162  const global_ordinal_type indexBase,
163  const Teuchos::RCP<const Teuchos::Comm<int> > &comm,
164  const LocalGlobal lOrG,
165  const Teuchos::RCP<Node> &/* node */) :
166  Map<LocalOrdinal,GlobalOrdinal,Node>::Map(numGlobalElements, indexBase,
167  comm, lOrG)
168  {}
169 #endif // TPETRA_ENABLE_DEPRECATED_CODE
170 
171  template <class LocalOrdinal, class GlobalOrdinal, class Node>
173  Map (const global_size_t numGlobalElements,
174  const global_ordinal_type indexBase,
175  const Teuchos::RCP<const Teuchos::Comm<int> > &comm,
176  const LocalGlobal lOrG) :
177  comm_ (comm),
178  uniform_ (true),
179  directory_ (new Directory<LocalOrdinal, GlobalOrdinal, Node> ())
180  {
181  using Teuchos::as;
182  using Teuchos::broadcast;
183  using Teuchos::outArg;
184  using Teuchos::reduceAll;
185  using Teuchos::REDUCE_MIN;
186  using Teuchos::REDUCE_MAX;
187  using Teuchos::typeName;
188  using GO = global_ordinal_type;
189  using GST = global_size_t;
190  const GST GSTI = Tpetra::Details::OrdinalTraits<GST>::invalid ();
191 
193 
194 #ifdef HAVE_TPETRA_DEBUG
195  // In debug mode only, check whether numGlobalElements and
196  // indexBase are the same over all processes in the communicator.
197  {
198  GST proc0NumGlobalElements = numGlobalElements;
199  broadcast<int, GST> (*comm_, 0, outArg (proc0NumGlobalElements));
200  GST minNumGlobalElements = numGlobalElements;
201  GST maxNumGlobalElements = numGlobalElements;
202  reduceAll<int, GST> (*comm, REDUCE_MIN, numGlobalElements, outArg (minNumGlobalElements));
203  reduceAll<int, GST> (*comm, REDUCE_MAX, numGlobalElements, outArg (maxNumGlobalElements));
204  TEUCHOS_TEST_FOR_EXCEPTION(
205  minNumGlobalElements != maxNumGlobalElements || numGlobalElements != minNumGlobalElements,
206  std::invalid_argument,
207  "Tpetra::Map constructor: All processes must provide the same number "
208  "of global elements. Process 0 set numGlobalElements = "
209  << proc0NumGlobalElements << ". The calling process "
210  << comm->getRank () << " set numGlobalElements = " << numGlobalElements
211  << ". The min and max values over all processes are "
212  << minNumGlobalElements << " resp. " << maxNumGlobalElements << ".");
213 
214  GO proc0IndexBase = indexBase;
215  broadcast<int, GO> (*comm_, 0, outArg (proc0IndexBase));
216  GO minIndexBase = indexBase;
217  GO maxIndexBase = indexBase;
218  reduceAll<int, GO> (*comm, REDUCE_MIN, indexBase, outArg (minIndexBase));
219  reduceAll<int, GO> (*comm, REDUCE_MAX, indexBase, outArg (maxIndexBase));
220  TEUCHOS_TEST_FOR_EXCEPTION(
221  minIndexBase != maxIndexBase || indexBase != minIndexBase,
222  std::invalid_argument,
223  "Tpetra::Map constructor: "
224  "All processes must provide the same indexBase argument. "
225  "Process 0 set indexBase = " << proc0IndexBase << ". The calling "
226  "process " << comm->getRank () << " set indexBase = " << indexBase
227  << ". The min and max values over all processes are "
228  << minIndexBase << " resp. " << maxIndexBase << ".");
229  }
230 #endif // HAVE_TPETRA_DEBUG
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.
249  TEUCHOS_TEST_FOR_EXCEPTION(
250  (numGlobalElements < 1 && numGlobalElements != 0),
251  std::invalid_argument,
252  "Tpetra::Map constructor: numGlobalElements (= "
253  << numGlobalElements << ") must be nonnegative.");
254 
255  TEUCHOS_TEST_FOR_EXCEPTION(
256  numGlobalElements == GSTI, std::invalid_argument,
257  "Tpetra::Map constructor: You provided numGlobalElements = Teuchos::"
258  "OrdinalTraits<Tpetra::global_size_t>::invalid(). This version of the "
259  "constructor requires a valid value of numGlobalElements. You "
260  "probably mistook this constructor for the \"contiguous nonuniform\" "
261  "constructor, which can compute the global number of elements for you "
262  "if you set numGlobalElements to that value.");
263 
264  size_t numLocalElements = 0; // will set below
265  if (lOrG == GloballyDistributed) {
266  // Compute numLocalElements:
267  //
268  // If numGlobalElements == numProcs * B + remainder,
269  // then Proc r gets B+1 elements if r < remainder,
270  // and B elements if r >= remainder.
271  //
272  // This strategy is valid for any value of numGlobalElements and
273  // numProcs, including the following border cases:
274  // - numProcs == 1
275  // - numLocalElements < numProcs
276  //
277  // In the former case, remainder == 0 && numGlobalElements ==
278  // numLocalElements. In the latter case, remainder ==
279  // numGlobalElements && numLocalElements is either 0 or 1.
280  const GST numProcs = static_cast<GST> (comm_->getSize ());
281  const GST myRank = static_cast<GST> (comm_->getRank ());
282  const GST quotient = numGlobalElements / numProcs;
283  const GST remainder = numGlobalElements - quotient * numProcs;
284 
285  GO startIndex;
286  if (myRank < remainder) {
287  numLocalElements = static_cast<size_t> (1) + static_cast<size_t> (quotient);
288  // myRank was originally an int, so it should never overflow
289  // reasonable GO types.
290  startIndex = as<GO> (myRank) * as<GO> (numLocalElements);
291  } else {
292  numLocalElements = as<size_t> (quotient);
293  startIndex = as<GO> (myRank) * as<GO> (numLocalElements) +
294  as<GO> (remainder);
295  }
296 
297  minMyGID_ = indexBase + startIndex;
298  maxMyGID_ = indexBase + startIndex + numLocalElements - 1;
299  minAllGID_ = indexBase;
300  maxAllGID_ = indexBase + numGlobalElements - 1;
301  distributed_ = (numProcs > 1);
302  }
303  else { // lOrG == LocallyReplicated
304  numLocalElements = as<size_t> (numGlobalElements);
305  minMyGID_ = indexBase;
306  maxMyGID_ = indexBase + numGlobalElements - 1;
307  distributed_ = false;
308  }
309 
310  minAllGID_ = indexBase;
311  maxAllGID_ = indexBase + numGlobalElements - 1;
312  indexBase_ = indexBase;
313  numGlobalElements_ = numGlobalElements;
314  numLocalElements_ = numLocalElements;
315  firstContiguousGID_ = minMyGID_;
316  lastContiguousGID_ = maxMyGID_;
317  contiguous_ = true;
318 
319  // Create the Directory on demand in getRemoteIndexList().
320  //setupDirectory ();
321  }
322 
323 #ifdef TPETRA_ENABLE_DEPRECATED_CODE
324  template <class LocalOrdinal, class GlobalOrdinal, class Node>
325  TPETRA_DEPRECATED
327  Map (const global_size_t numGlobalElements,
328  const size_t numLocalElements,
329  const global_ordinal_type indexBase,
330  const Teuchos::RCP<const Teuchos::Comm<int> > &comm,
331  const Teuchos::RCP<Node> &/* node */) :
332  Map<LocalOrdinal,GlobalOrdinal,Node>::Map(numGlobalElements,
333  numLocalElements,
334  indexBase, comm)
335  {}
336 #endif // TPETRA_ENABLE_DEPRECATED_CODE
337 
338  template <class LocalOrdinal, class GlobalOrdinal, class Node>
340  Map (const global_size_t numGlobalElements,
341  const size_t numLocalElements,
342  const global_ordinal_type indexBase,
343  const Teuchos::RCP<const Teuchos::Comm<int> > &comm) :
344  comm_ (comm),
345  uniform_ (false),
346  directory_ (new Directory<LocalOrdinal, GlobalOrdinal, Node> ())
347  {
348  using Teuchos::as;
349  using Teuchos::broadcast;
350  using Teuchos::outArg;
351  using Teuchos::reduceAll;
352  using Teuchos::REDUCE_MIN;
353  using Teuchos::REDUCE_MAX;
354  using Teuchos::REDUCE_SUM;
355  using Teuchos::scan;
356  using GO = global_ordinal_type;
357  using GST = global_size_t;
358  const GST GSTI = Tpetra::Details::OrdinalTraits<GST>::invalid ();
359 
361 
362 #ifdef HAVE_TPETRA_DEBUG
363  // Global sum of numLocalElements over all processes.
364  // Keep this for later debug checks.
365  const GST debugGlobalSum =
366  initialNonuniformDebugCheck (numGlobalElements, numLocalElements,
367  indexBase, comm);
368 #endif // HAVE_TPETRA_DEBUG
369 
370  // Distribute the elements across the nodes so that they are
371  // - non-overlapping
372  // - contiguous
373 
374  // This differs from the first Map constructor (that only takes a
375  // global number of elements) in that the user has specified the
376  // number of local elements, so that the elements are not
377  // (necessarily) evenly distributed over the processes.
378 
379  // Compute my local offset. This is an inclusive scan, so to get
380  // the final offset, we subtract off the input.
381  GO scanResult = 0;
382  scan<int, GO> (*comm, REDUCE_SUM, numLocalElements, outArg (scanResult));
383  const GO myOffset = scanResult - numLocalElements;
384 
385  if (numGlobalElements != GSTI) {
386  numGlobalElements_ = numGlobalElements; // Use the user's value.
387  } else {
388  // Inclusive scan means that the last process has the final sum.
389  // Rather than doing a reduceAll to get the sum of
390  // numLocalElements, we can just have the last process broadcast
391  // its result. That saves us a round of log(numProcs) messages.
392  const int numProcs = comm->getSize ();
393  GST globalSum = scanResult;
394  if (numProcs > 1) {
395  broadcast (*comm, numProcs - 1, outArg (globalSum));
396  }
397  numGlobalElements_ = globalSum;
398 
399 #ifdef HAVE_TPETRA_DEBUG
400  // No need for an all-reduce here; both come from collectives.
401  TEUCHOS_TEST_FOR_EXCEPTION(
402  globalSum != debugGlobalSum, std::logic_error,
403  "Tpetra::Map constructor (contiguous nonuniform): "
404  "globalSum = " << globalSum << " != debugGlobalSum = " << debugGlobalSum
405  << ". Please report this bug to the Tpetra developers.");
406 #endif // HAVE_TPETRA_DEBUG
407  }
408  numLocalElements_ = numLocalElements;
409  indexBase_ = indexBase;
410  minAllGID_ = (numGlobalElements_ == 0) ?
411  std::numeric_limits<GO>::max () :
412  indexBase;
413  maxAllGID_ = (numGlobalElements_ == 0) ?
414  std::numeric_limits<GO>::lowest () :
415  indexBase + static_cast<GO> (numGlobalElements_) - static_cast<GO> (1);
416  minMyGID_ = (numLocalElements_ == 0) ?
417  std::numeric_limits<GO>::max () :
418  indexBase + static_cast<GO> (myOffset);
419  maxMyGID_ = (numLocalElements_ == 0) ?
420  std::numeric_limits<GO>::lowest () :
421  indexBase + myOffset + static_cast<GO> (numLocalElements) - static_cast<GO> (1);
422  firstContiguousGID_ = minMyGID_;
423  lastContiguousGID_ = maxMyGID_;
424  contiguous_ = true;
425  distributed_ = checkIsDist ();
426 
427  // Create the Directory on demand in getRemoteIndexList().
428  //setupDirectory ();
429  }
430 
431  template <class LocalOrdinal, class GlobalOrdinal, class Node>
433  Map<LocalOrdinal,GlobalOrdinal,Node>::
434  initialNonuniformDebugCheck (const global_size_t numGlobalElements,
435  const size_t numLocalElements,
436  const GlobalOrdinal indexBase,
437  const Teuchos::RCP<const Teuchos::Comm<int> >& comm) const
438  {
439 #ifdef HAVE_TPETRA_DEBUG
440  using Teuchos::broadcast;
441  using Teuchos::outArg;
442  using Teuchos::ptr;
443  using Teuchos::REDUCE_MAX;
444  using Teuchos::REDUCE_MIN;
445  using Teuchos::REDUCE_SUM;
446  using Teuchos::reduceAll;
447  typedef GlobalOrdinal GO;
448  typedef global_size_t GST;
449  const GST GSTI = Tpetra::Details::OrdinalTraits<GST>::invalid ();
450 
451  // The user has specified the distribution of indices over the
452  // processes. The distribution is not necessarily contiguous or
453  // equally shared over the processes.
454  //
455  // We assume that the number of local elements can be stored in a
456  // size_t. The instance member numLocalElements_ is a size_t, so
457  // this variable and that should have the same type.
458 
459  GST debugGlobalSum = 0; // Will be global sum of numLocalElements
460  reduceAll<int, GST> (*comm, REDUCE_SUM, static_cast<GST> (numLocalElements),
461  outArg (debugGlobalSum));
462  // In debug mode only, check whether numGlobalElements and
463  // indexBase are the same over all processes in the communicator.
464  {
465  GST proc0NumGlobalElements = numGlobalElements;
466  broadcast<int, GST> (*comm_, 0, outArg (proc0NumGlobalElements));
467  GST minNumGlobalElements = numGlobalElements;
468  GST maxNumGlobalElements = numGlobalElements;
469  reduceAll<int, GST> (*comm, REDUCE_MIN, numGlobalElements,
470  outArg (minNumGlobalElements));
471  reduceAll<int, GST> (*comm, REDUCE_MAX, numGlobalElements,
472  outArg (maxNumGlobalElements));
473  TEUCHOS_TEST_FOR_EXCEPTION(
474  minNumGlobalElements != maxNumGlobalElements ||
475  numGlobalElements != minNumGlobalElements,
476  std::invalid_argument,
477  "Tpetra::Map constructor: All processes must provide the same number "
478  "of global elements. This is true even if that argument is Teuchos::"
479  "OrdinalTraits<global_size_t>::invalid() to signal that the Map should "
480  "compute the global number of elements. Process 0 set numGlobalElements"
481  " = " << proc0NumGlobalElements << ". The calling process "
482  << comm->getRank () << " set numGlobalElements = " << numGlobalElements
483  << ". The min and max values over all processes are "
484  << minNumGlobalElements << " resp. " << maxNumGlobalElements << ".");
485 
486  GO proc0IndexBase = indexBase;
487  broadcast<int, GO> (*comm_, 0, outArg (proc0IndexBase));
488  GO minIndexBase = indexBase;
489  GO maxIndexBase = indexBase;
490  reduceAll<int, GO> (*comm, REDUCE_MIN, indexBase, outArg (minIndexBase));
491  reduceAll<int, GO> (*comm, REDUCE_MAX, indexBase, outArg (maxIndexBase));
492  TEUCHOS_TEST_FOR_EXCEPTION(
493  minIndexBase != maxIndexBase || indexBase != minIndexBase,
494  std::invalid_argument,
495  "Tpetra::Map constructor: "
496  "All processes must provide the same indexBase argument. "
497  "Process 0 set indexBase = " << proc0IndexBase << ". The calling "
498  "process " << comm->getRank () << " set indexBase = " << indexBase
499  << ". The min and max values over all processes are "
500  << minIndexBase << " resp. " << maxIndexBase << ".");
501 
502  // Make sure that the sum of numLocalElements over all processes
503  // equals numGlobalElements.
504  TEUCHOS_TEST_FOR_EXCEPTION
505  (numGlobalElements != GSTI && debugGlobalSum != numGlobalElements,
506  std::invalid_argument, "Tpetra::Map constructor: The sum of each "
507  "process' number of indices over all processes, " << debugGlobalSum
508  << " != numGlobalElements = " << numGlobalElements << ". If you "
509  "would like this constructor to compute numGlobalElements for you, "
510  "you may set numGlobalElements = "
511  "Teuchos::OrdinalTraits<Tpetra::global_size_t>::invalid() on input. "
512  "Please note that this is NOT necessarily -1.");
513  }
514 
515  return debugGlobalSum;
516 #else
517  (void)numGlobalElements;
518  (void)numLocalElements;
519  (void)indexBase;
520  (void)comm;
521  return static_cast<global_size_t> (0);
522 #endif // HAVE_TPETRA_DEBUG
523  }
524 
525  template <class LocalOrdinal, class GlobalOrdinal, class Node>
526  void
527  Map<LocalOrdinal,GlobalOrdinal,Node>::
528  initWithNonownedHostIndexList (const global_size_t numGlobalElements,
529  const Kokkos::View<const GlobalOrdinal*,
530  Kokkos::LayoutLeft,
531  Kokkos::HostSpace,
532  Kokkos::MemoryUnmanaged>& entryList_host,
533  const GlobalOrdinal indexBase,
534  const Teuchos::RCP<const Teuchos::Comm<int> >& comm)
535  {
536  using Kokkos::LayoutLeft;
537  using Kokkos::subview;
538  using Kokkos::View;
539  using Kokkos::view_alloc;
540  using Kokkos::WithoutInitializing;
541  using Teuchos::as;
542  using Teuchos::broadcast;
543  using Teuchos::outArg;
544  using Teuchos::ptr;
545  using Teuchos::REDUCE_MAX;
546  using Teuchos::REDUCE_MIN;
547  using Teuchos::REDUCE_SUM;
548  using Teuchos::reduceAll;
549  using LO = LocalOrdinal;
550  using GO = GlobalOrdinal;
551  using GST = global_size_t;
552  const GST GSTI = Tpetra::Details::OrdinalTraits<GST>::invalid ();
553 
554  // Make sure that Kokkos has been initialized (Github Issue #513).
555  TEUCHOS_TEST_FOR_EXCEPTION
556  (! Kokkos::is_initialized (), std::runtime_error,
557  "Tpetra::Map constructor: The Kokkos execution space "
558  << Teuchos::TypeNameTraits<execution_space>::name ()
559  << " has not been initialized. "
560  "Please initialize it before creating a Map.")
561 
562  // The user has specified the distribution of indices over the
563  // processes, via the input array of global indices on each
564  // process. The distribution is not necessarily contiguous or
565  // equally shared over the processes.
566 
567  // The length of the input array on this process is the number of
568  // local indices to associate with this process, even though the
569  // input array contains global indices. We assume that the number
570  // of local indices on a process can be stored in a size_t;
571  // numLocalElements_ is a size_t, so this variable and that should
572  // have the same type.
573  const size_t numLocalElements = static_cast<size_t> (entryList_host.size ());
574 
575  initialNonuniformDebugCheck (numGlobalElements, numLocalElements,
576  indexBase, comm);
577 
578  // NOTE (mfh 20 Feb 2013, 10 Oct 2016) In some sense, this global
579  // reduction is redundant, since the directory Map will have to do
580  // the same thing. Thus, we could do the scan and broadcast for
581  // the directory Map here, and give the computed offsets to the
582  // directory Map's constructor. However, a reduction costs less
583  // than a scan and broadcast, so this still saves time if users of
584  // this Map don't ever need the Directory (i.e., if they never
585  // call getRemoteIndexList on this Map).
586  if (numGlobalElements != GSTI) {
587  numGlobalElements_ = numGlobalElements; // Use the user's value.
588  }
589  else { // The user wants us to compute the sum.
590  reduceAll<int, GST> (*comm, REDUCE_SUM,
591  static_cast<GST> (numLocalElements),
592  outArg (numGlobalElements_));
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  // Find contiguous GID range, with the restriction that the
634  // beginning of the range starts with the first entry. While
635  // doing so, fill in the LID -> GID table.
636  typename decltype (lgMap_)::non_const_type lgMap
637  (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.
668  lgMap_host[curLid] = curGid;
669  ++lastContiguousGID_;
670  }
671  --lastContiguousGID_;
672 
673  // [firstContiguousGID_, lastContigousGID_] is the initial
674  // sequence of contiguous GIDs. We can start the min and max
675  // GID using this range.
676  minMyGID_ = firstContiguousGID_;
677  maxMyGID_ = lastContiguousGID_;
678 
679  // Compute the GID -> LID lookup table, _not_ including the
680  // initial sequence of contiguous GIDs.
681  {
682  const std::pair<size_t, size_t> ncRange (i, entryList_host.extent (0));
683  auto nonContigGids_host = subview (entryList_host, ncRange);
684  TEUCHOS_TEST_FOR_EXCEPTION
685  (static_cast<size_t> (nonContigGids_host.extent (0)) !=
686  static_cast<size_t> (entryList_host.extent (0) - i),
687  std::logic_error, "Tpetra::Map noncontiguous constructor: "
688  "nonContigGids_host.extent(0) = "
689  << nonContigGids_host.extent (0)
690  << " != entryList_host.extent(0) - i = "
691  << (entryList_host.extent (0) - i) << " = "
692  << entryList_host.extent (0) << " - " << i
693  << ". Please report this bug to the Tpetra developers.");
694 
695  // FixedHashTable's constructor expects an owned device View,
696  // so we must deep-copy the subview of the input indices.
697  View<GO*, LayoutLeft, device_type>
698  nonContigGids (view_alloc ("nonContigGids", WithoutInitializing),
699  nonContigGids_host.size ());
700  Kokkos::deep_copy (nonContigGids, nonContigGids_host);
701 
702  glMap_ = global_to_local_table_type (nonContigGids,
703  firstContiguousGID_,
704  lastContiguousGID_,
705  static_cast<LO> (i));
706  }
707 
708  // FIXME (mfh 10 Oct 2016) When we construct the global-to-local
709  // table above, we have to look at all the (noncontiguous) input
710  // indices anyway. Thus, why not have the constructor compute
711  // and return the min and max?
712 
713  for ( ; i < numLocalElements_; ++i) {
714  const GO curGid = entryList_host[i];
715  const LO curLid = static_cast<LO> (i);
716  lgMap_host[curLid] = curGid; // LID -> GID table
717 
718  // While iterating through entryList, we compute its
719  // (process-local) min and max elements.
720  if (curGid < minMyGID_) {
721  minMyGID_ = curGid;
722  }
723  if (curGid > maxMyGID_) {
724  maxMyGID_ = curGid;
725  }
726  }
727 
728  // We filled lgMap on host above; now sync back to device.
729  Kokkos::deep_copy (lgMap, lgMap_host);
730 
731  // "Commit" the local-to-global lookup table we filled in above.
732  lgMap_ = lgMap;
733  // We've already created this, so use it.
734  lgMapHost_ = lgMap_host;
735  }
736  else {
737  minMyGID_ = std::numeric_limits<GlobalOrdinal>::max();
738  maxMyGID_ = std::numeric_limits<GlobalOrdinal>::lowest();
739  // This insures tests for GIDs in the range
740  // [firstContiguousGID_, lastContiguousGID_] fail for processes
741  // with no local elements.
742  firstContiguousGID_ = indexBase_+1;
743  lastContiguousGID_ = indexBase_;
744  // glMap_ was default constructed, so it's already empty.
745  }
746 
747  // Compute the min and max of all processes' GIDs. If
748  // numLocalElements_ == 0 on this process, minMyGID_ and maxMyGID_
749  // are both indexBase_. This is wrong, but fixing it would
750  // require either a fancy sparse all-reduce, or a custom reduction
751  // operator that ignores invalid values ("invalid" means
752  // Tpetra::Details::OrdinalTraits<GO>::invalid()).
753  //
754  // Also, while we're at it, use the same all-reduce to figure out
755  // if the Map is distributed. "Distributed" means that there is
756  // at least one process with a number of local elements less than
757  // the number of global elements.
758  //
759  // We're computing the min and max of all processes' GIDs using a
760  // single MAX all-reduce, because min(x,y) = -max(-x,-y) (when x
761  // and y are signed). (This lets us combine the min and max into
762  // a single all-reduce.) If each process sets localDist=1 if its
763  // number of local elements is strictly less than the number of
764  // global elements, and localDist=0 otherwise, then a MAX
765  // all-reduce on localDist tells us if the Map is distributed (1
766  // if yes, 0 if no). Thus, we can append localDist onto the end
767  // of the data and get the global result from the all-reduce.
768  if (std::numeric_limits<GO>::is_signed) {
769  // Does my process NOT own all the elements?
770  const GO localDist =
771  (as<GST> (numLocalElements_) < numGlobalElements_) ? 1 : 0;
772 
773  GO minMaxInput[3];
774  minMaxInput[0] = -minMyGID_;
775  minMaxInput[1] = maxMyGID_;
776  minMaxInput[2] = localDist;
777 
778  GO minMaxOutput[3];
779  minMaxOutput[0] = 0;
780  minMaxOutput[1] = 0;
781  minMaxOutput[2] = 0;
782  reduceAll<int, GO> (*comm, REDUCE_MAX, 3, minMaxInput, minMaxOutput);
783  minAllGID_ = -minMaxOutput[0];
784  maxAllGID_ = minMaxOutput[1];
785  const GO globalDist = minMaxOutput[2];
786  distributed_ = (comm_->getSize () > 1 && globalDist == 1);
787  }
788  else { // unsigned; use two reductions
789  // This is always correct, no matter the signedness of GO.
790  reduceAll<int, GO> (*comm_, REDUCE_MIN, minMyGID_, outArg (minAllGID_));
791  reduceAll<int, GO> (*comm_, REDUCE_MAX, maxMyGID_, outArg (maxAllGID_));
792  distributed_ = checkIsDist ();
793  }
794 
795  contiguous_ = false; // "Contiguous" is conservative.
796 
797  TEUCHOS_TEST_FOR_EXCEPTION(
798  minAllGID_ < indexBase_,
799  std::invalid_argument,
800  "Tpetra::Map constructor (noncontiguous): "
801  "Minimum global ID = " << minAllGID_ << " over all process(es) is "
802  "less than the given indexBase = " << indexBase_ << ".");
803 
804  // Create the Directory on demand in getRemoteIndexList().
805  //setupDirectory ();
806  }
807 
808  template <class LocalOrdinal, class GlobalOrdinal, class Node>
810  Map (const global_size_t numGlobalElements,
811  const GlobalOrdinal indexList[],
812  const LocalOrdinal indexListSize,
813  const GlobalOrdinal indexBase,
814  const Teuchos::RCP<const Teuchos::Comm<int> >& comm) :
815  comm_ (comm),
816  uniform_ (false),
817  directory_ (new Directory<LocalOrdinal, GlobalOrdinal, Node> ())
818  {
820  checkMapInputArray ("(GST, const GO[], LO, GO, comm)",
821  indexList, static_cast<size_t> (indexListSize),
822  Kokkos::DefaultHostExecutionSpace (),
823  comm.getRawPtr ());
824  // Not quite sure if I trust all code to behave correctly if the
825  // pointer is nonnull but the array length is nonzero, so I'll
826  // make sure the raw pointer is null if the length is zero.
827  const GlobalOrdinal* const indsRaw = indexListSize == 0 ? NULL : indexList;
828  Kokkos::View<const GlobalOrdinal*,
829  Kokkos::LayoutLeft,
830  Kokkos::HostSpace,
831  Kokkos::MemoryUnmanaged> inds (indsRaw, indexListSize);
832  initWithNonownedHostIndexList (numGlobalElements, inds, indexBase, comm);
833  }
834 
835 #ifdef TPETRA_ENABLE_DEPRECATED_CODE
836  template <class LocalOrdinal, class GlobalOrdinal, class Node>
838  Map (const global_size_t numGlobalElements,
839  const Teuchos::ArrayView<const GlobalOrdinal>& entryList,
840  const GlobalOrdinal indexBase,
841  const Teuchos::RCP<const Teuchos::Comm<int> >& comm,
842  const Teuchos::RCP<Node>& /* node */) :
843  Map<LocalOrdinal,GlobalOrdinal,Node>::Map(numGlobalElements, entryList,
844  indexBase, comm)
845  {}
846 #endif // TPETRA_ENABLE_DEPRECATED_CODE
847 
848  template <class LocalOrdinal, class GlobalOrdinal, class Node>
850  Map (const global_size_t numGlobalElements,
851  const Teuchos::ArrayView<const GlobalOrdinal>& entryList,
852  const GlobalOrdinal indexBase,
853  const Teuchos::RCP<const Teuchos::Comm<int> >& comm) :
854  comm_ (comm),
855  uniform_ (false),
856  directory_ (new Directory<LocalOrdinal, GlobalOrdinal, Node> ())
857  {
859  const size_t numLclInds = static_cast<size_t> (entryList.size ());
860  checkMapInputArray ("(GST, ArrayView, GO, comm)",
861  entryList.getRawPtr (), numLclInds,
862  Kokkos::DefaultHostExecutionSpace (),
863  comm.getRawPtr ());
864  // Not quite sure if I trust both ArrayView and View to behave
865  // correctly if the pointer is nonnull but the array length is
866  // nonzero, so I'll make sure it's null if the length is zero.
867  const GlobalOrdinal* const indsRaw =
868  numLclInds == 0 ? NULL : entryList.getRawPtr ();
869  Kokkos::View<const GlobalOrdinal*,
870  Kokkos::LayoutLeft,
871  Kokkos::HostSpace,
872  Kokkos::MemoryUnmanaged> inds (indsRaw, numLclInds);
873  initWithNonownedHostIndexList (numGlobalElements, inds, indexBase, comm);
874  }
875 
876  template <class LocalOrdinal, class GlobalOrdinal, class Node>
878  Map (const global_size_t numGlobalElements,
879  const Kokkos::View<const GlobalOrdinal*, device_type>& entryList,
880  const GlobalOrdinal indexBase,
881  const Teuchos::RCP<const Teuchos::Comm<int> >& comm) :
882  comm_ (comm),
883  uniform_ (false),
884  directory_ (new Directory<LocalOrdinal, GlobalOrdinal, Node> ())
885  {
886  using Kokkos::LayoutLeft;
887  using Kokkos::subview;
888  using Kokkos::View;
889  using Kokkos::view_alloc;
890  using Kokkos::WithoutInitializing;
891  using Teuchos::arcp;
892  using Teuchos::ArrayView;
893  using Teuchos::as;
894  using Teuchos::broadcast;
895  using Teuchos::outArg;
896  using Teuchos::ptr;
897  using Teuchos::REDUCE_MAX;
898  using Teuchos::REDUCE_MIN;
899  using Teuchos::REDUCE_SUM;
900  using Teuchos::reduceAll;
901  using Teuchos::typeName;
902  typedef LocalOrdinal LO;
903  typedef GlobalOrdinal GO;
904  typedef global_size_t GST;
905  const GST GSTI = Tpetra::Details::OrdinalTraits<GST>::invalid ();
906 
908  checkMapInputArray ("(GST, Kokkos::View, GO, comm)",
909  entryList.data (),
910  static_cast<size_t> (entryList.extent (0)),
911  execution_space (), comm.getRawPtr ());
912 
913  // The user has specified the distribution of indices over the
914  // processes, via the input array of global indices on each
915  // process. The distribution is not necessarily contiguous or
916  // equally shared over the processes.
917 
918  // The length of the input array on this process is the number of
919  // local indices to associate with this process, even though the
920  // input array contains global indices. We assume that the number
921  // of local indices on a process can be stored in a size_t;
922  // numLocalElements_ is a size_t, so this variable and that should
923  // have the same type.
924  const size_t numLocalElements = static_cast<size_t> (entryList.size ());
925 
926  initialNonuniformDebugCheck (numGlobalElements, numLocalElements,
927  indexBase, comm);
928 
929  // NOTE (mfh 20 Feb 2013, 10 Oct 2016) In some sense, this global
930  // reduction is redundant, since the directory Map will have to do
931  // the same thing. Thus, we could do the scan and broadcast for
932  // the directory Map here, and give the computed offsets to the
933  // directory Map's constructor. However, a reduction costs less
934  // than a scan and broadcast, so this still saves time if users of
935  // this Map don't ever need the Directory (i.e., if they never
936  // call getRemoteIndexList on this Map).
937  if (numGlobalElements != GSTI) {
938  numGlobalElements_ = numGlobalElements; // Use the user's value.
939  }
940  else { // The user wants us to compute the sum.
941  reduceAll<int, GST> (*comm, REDUCE_SUM,
942  static_cast<GST> (numLocalElements),
943  outArg (numGlobalElements_));
944  }
945 
946  // mfh 20 Feb 2013: We've never quite done the right thing for
947  // duplicate GIDs here. Duplicate GIDs have always been counted
948  // distinctly in numLocalElements_, and thus should get a
949  // different LID. However, we've always used std::map or a hash
950  // table for the GID -> LID lookup table, so distinct GIDs always
951  // map to the same LID. Furthermore, the order of the input GID
952  // list matters, so it's not desirable to sort for determining
953  // uniqueness.
954  //
955  // I've chosen for now to write this code as if the input GID list
956  // contains no duplicates. If this is not desired, we could use
957  // the lookup table itself to determine uniqueness: If we haven't
958  // seen the GID before, it gets a new LID and it's added to the
959  // LID -> GID and GID -> LID tables. If we have seen the GID
960  // before, it doesn't get added to either table. I would
961  // implement this, but it would cost more to do the double lookups
962  // in the table (one to check, and one to insert).
963  //
964  // More importantly, since we build the GID -> LID table in (a
965  // thread-) parallel (way), the order in which duplicate GIDs may
966  // get inserted is not defined. This would make the assignment of
967  // LID to GID nondeterministic.
968 
969  numLocalElements_ = numLocalElements;
970  indexBase_ = indexBase;
971 
972  minMyGID_ = indexBase_;
973  maxMyGID_ = indexBase_;
974 
975  // NOTE (mfh 27 May 2015): While finding the initial contiguous
976  // GID range requires looking at all the GIDs in the range,
977  // dismissing an interval of GIDs only requires looking at the
978  // first and last GIDs. Thus, we could do binary search backwards
979  // from the end in order to catch the common case of a contiguous
980  // interval followed by noncontiguous entries. On the other hand,
981  // we could just expose this case explicitly as yet another Map
982  // constructor, and avoid the trouble of detecting it.
983  if (numLocalElements_ > 0) {
984  // Find contiguous GID range, with the restriction that the
985  // beginning of the range starts with the first entry. While
986  // doing so, fill in the LID -> GID table.
987  typename decltype (lgMap_)::non_const_type lgMap
988  (view_alloc ("lgMap", WithoutInitializing), numLocalElements_);
989  auto lgMap_host =
990  Kokkos::create_mirror_view (Kokkos::HostSpace (), lgMap);
991 
992  using array_layout =
993  typename View<const GO*, device_type>::array_layout;
994  View<GO*, array_layout, Kokkos::HostSpace> entryList_host
995  (view_alloc ("entryList_host", WithoutInitializing),
996  entryList.extent(0));
997  Kokkos::deep_copy (entryList_host, entryList);
998 
999  firstContiguousGID_ = entryList_host[0];
1000  lastContiguousGID_ = firstContiguousGID_+1;
1001 
1002  // FIXME (mfh 23 Sep 2015) We need to copy the input GIDs
1003  // anyway, so we have to look at them all. The logical way to
1004  // find the first noncontiguous entry would thus be to "reduce,"
1005  // where the local reduction result is whether entryList[i] + 1
1006  // == entryList[i+1].
1007 
1008  lgMap_host[0] = firstContiguousGID_;
1009  size_t i = 1;
1010  for ( ; i < numLocalElements_; ++i) {
1011  const GO curGid = entryList_host[i];
1012  const LO curLid = as<LO> (i);
1013 
1014  if (lastContiguousGID_ != curGid) break;
1015 
1016  // Add the entry to the LID->GID table only after we know that
1017  // the current GID is in the initial contiguous sequence, so
1018  // that we don't repeat adding it in the first iteration of
1019  // the loop below over the remaining noncontiguous GIDs.
1020  lgMap_host[curLid] = curGid;
1021  ++lastContiguousGID_;
1022  }
1023  --lastContiguousGID_;
1024 
1025  // [firstContiguousGID_, lastContigousGID_] is the initial
1026  // sequence of contiguous GIDs. We can start the min and max
1027  // GID using this range.
1028  minMyGID_ = firstContiguousGID_;
1029  maxMyGID_ = lastContiguousGID_;
1030 
1031  // Compute the GID -> LID lookup table, _not_ including the
1032  // initial sequence of contiguous GIDs.
1033  {
1034  const std::pair<size_t, size_t> ncRange (i, entryList.extent (0));
1035  auto nonContigGids = subview (entryList, ncRange);
1036  TEUCHOS_TEST_FOR_EXCEPTION
1037  (static_cast<size_t> (nonContigGids.extent (0)) !=
1038  static_cast<size_t> (entryList.extent (0) - i),
1039  std::logic_error, "Tpetra::Map noncontiguous constructor: "
1040  "nonContigGids.extent(0) = "
1041  << nonContigGids.extent (0)
1042  << " != entryList.extent(0) - i = "
1043  << (entryList.extent (0) - i) << " = "
1044  << entryList.extent (0) << " - " << i
1045  << ". Please report this bug to the Tpetra developers.");
1046 
1047  glMap_ = global_to_local_table_type (nonContigGids,
1048  firstContiguousGID_,
1049  lastContiguousGID_,
1050  static_cast<LO> (i));
1051  }
1052 
1053  // FIXME (mfh 10 Oct 2016) When we construct the global-to-local
1054  // table above, we have to look at all the (noncontiguous) input
1055  // indices anyway. Thus, why not have the constructor compute
1056  // and return the min and max?
1057 
1058  for ( ; i < numLocalElements_; ++i) {
1059  const GO curGid = entryList_host[i];
1060  const LO curLid = static_cast<LO> (i);
1061  lgMap_host[curLid] = curGid; // LID -> GID table
1062 
1063  // While iterating through entryList, we compute its
1064  // (process-local) min and max elements.
1065  if (curGid < minMyGID_) {
1066  minMyGID_ = curGid;
1067  }
1068  if (curGid > maxMyGID_) {
1069  maxMyGID_ = curGid;
1070  }
1071  }
1072 
1073  // We filled lgMap on host above; now sync back to device.
1074  Kokkos::deep_copy (lgMap, lgMap_host);
1075 
1076  // "Commit" the local-to-global lookup table we filled in above.
1077  lgMap_ = lgMap;
1078  // We've already created this, so use it.
1079  lgMapHost_ = lgMap_host;
1080  }
1081  else {
1082  minMyGID_ = std::numeric_limits<GlobalOrdinal>::max();
1083  maxMyGID_ = std::numeric_limits<GlobalOrdinal>::lowest();
1084  // This insures tests for GIDs in the range
1085  // [firstContiguousGID_, lastContiguousGID_] fail for processes
1086  // with no local elements.
1087  firstContiguousGID_ = indexBase_+1;
1088  lastContiguousGID_ = indexBase_;
1089  // glMap_ was default constructed, so it's already empty.
1090  }
1091 
1092  // Compute the min and max of all processes' GIDs. If
1093  // numLocalElements_ == 0 on this process, minMyGID_ and maxMyGID_
1094  // are both indexBase_. This is wrong, but fixing it would
1095  // require either a fancy sparse all-reduce, or a custom reduction
1096  // operator that ignores invalid values ("invalid" means
1097  // Tpetra::Details::OrdinalTraits<GO>::invalid()).
1098  //
1099  // Also, while we're at it, use the same all-reduce to figure out
1100  // if the Map is distributed. "Distributed" means that there is
1101  // at least one process with a number of local elements less than
1102  // the number of global elements.
1103  //
1104  // We're computing the min and max of all processes' GIDs using a
1105  // single MAX all-reduce, because min(x,y) = -max(-x,-y) (when x
1106  // and y are signed). (This lets us combine the min and max into
1107  // a single all-reduce.) If each process sets localDist=1 if its
1108  // number of local elements is strictly less than the number of
1109  // global elements, and localDist=0 otherwise, then a MAX
1110  // all-reduce on localDist tells us if the Map is distributed (1
1111  // if yes, 0 if no). Thus, we can append localDist onto the end
1112  // of the data and get the global result from the all-reduce.
1113  if (std::numeric_limits<GO>::is_signed) {
1114  // Does my process NOT own all the elements?
1115  const GO localDist =
1116  (as<GST> (numLocalElements_) < numGlobalElements_) ? 1 : 0;
1117 
1118  GO minMaxInput[3];
1119  minMaxInput[0] = -minMyGID_;
1120  minMaxInput[1] = maxMyGID_;
1121  minMaxInput[2] = localDist;
1122 
1123  GO minMaxOutput[3];
1124  minMaxOutput[0] = 0;
1125  minMaxOutput[1] = 0;
1126  minMaxOutput[2] = 0;
1127  reduceAll<int, GO> (*comm, REDUCE_MAX, 3, minMaxInput, minMaxOutput);
1128  minAllGID_ = -minMaxOutput[0];
1129  maxAllGID_ = minMaxOutput[1];
1130  const GO globalDist = minMaxOutput[2];
1131  distributed_ = (comm_->getSize () > 1 && globalDist == 1);
1132  }
1133  else { // unsigned; use two reductions
1134  // This is always correct, no matter the signedness of GO.
1135  reduceAll<int, GO> (*comm_, REDUCE_MIN, minMyGID_, outArg (minAllGID_));
1136  reduceAll<int, GO> (*comm_, REDUCE_MAX, maxMyGID_, outArg (maxAllGID_));
1137  distributed_ = checkIsDist ();
1138  }
1139 
1140  contiguous_ = false; // "Contiguous" is conservative.
1141 
1142  TEUCHOS_TEST_FOR_EXCEPTION(
1143  minAllGID_ < indexBase_,
1144  std::invalid_argument,
1145  "Tpetra::Map constructor (noncontiguous): "
1146  "Minimum global ID = " << minAllGID_ << " over all process(es) is "
1147  "less than the given indexBase = " << indexBase_ << ".");
1148 
1149  // Create the Directory on demand in getRemoteIndexList().
1150  //setupDirectory ();
1151  }
1152 
1153 
1154  template <class LocalOrdinal, class GlobalOrdinal, class Node>
1156  {
1157  if (! Kokkos::is_initialized ()) {
1158  std::ostringstream os;
1159  os << "WARNING: Tpetra::Map destructor (~Map()) is being called after "
1160  "Kokkos::finalize() has been called. This is user error! There are "
1161  "two likely causes: " << std::endl <<
1162  " 1. You have a static Tpetra::Map (or RCP or shared_ptr of a Map)"
1163  << std::endl <<
1164  " 2. You declare and construct a Tpetra::Map (or RCP or shared_ptr "
1165  "of a Tpetra::Map) at the same scope in main() as Kokkos::finalize() "
1166  "or Tpetra::finalize()." << std::endl << std::endl <<
1167  "Don't do either of these! Please refer to GitHib Issue #2372."
1168  << std::endl;
1169  ::Tpetra::Details::printOnce (std::cerr, os.str (),
1170  this->getComm ().getRawPtr ());
1171  }
1172  else {
1173  using ::Tpetra::Details::mpiIsInitialized;
1174  using ::Tpetra::Details::mpiIsFinalized;
1175  using ::Tpetra::Details::teuchosCommIsAnMpiComm;
1176 
1177  Teuchos::RCP<const Teuchos::Comm<int> > comm = this->getComm ();
1178  if (! comm.is_null () && teuchosCommIsAnMpiComm (*comm) &&
1179  mpiIsInitialized () && mpiIsFinalized ()) {
1180  // Tpetra itself does not require MPI, even if building with
1181  // MPI. It is legal to create Tpetra objects that do not use
1182  // MPI, even in an MPI program. However, calling Tpetra stuff
1183  // after MPI_Finalize() has been called is a bad idea, since
1184  // some Tpetra defaults may use MPI if available.
1185  std::ostringstream os;
1186  os << "WARNING: Tpetra::Map destructor (~Map()) is being called after "
1187  "MPI_Finalize() has been called. This is user error! There are "
1188  "two likely causes: " << std::endl <<
1189  " 1. You have a static Tpetra::Map (or RCP or shared_ptr of a Map)"
1190  << std::endl <<
1191  " 2. You declare and construct a Tpetra::Map (or RCP or shared_ptr "
1192  "of a Tpetra::Map) at the same scope in main() as MPI_finalize() or "
1193  "Tpetra::finalize()." << std::endl << std::endl <<
1194  "Don't do either of these! Please refer to GitHib Issue #2372."
1195  << std::endl;
1196  ::Tpetra::Details::printOnce (std::cerr, os.str (), comm.getRawPtr ());
1197  }
1198  }
1199  // mfh 20 Mar 2018: We can't check Tpetra::isInitialized() yet,
1200  // because Tpetra does not yet require Tpetra::initialize /
1201  // Tpetra::finalize.
1202  }
1203 
1204 
1205  template <class LocalOrdinal, class GlobalOrdinal, class Node>
1206  bool
1208  {
1209  TEUCHOS_TEST_FOR_EXCEPTION(
1210  getComm ().is_null (), std::logic_error, "Tpetra::Map::isOneToOne: "
1211  "getComm() returns null. Please report this bug to the Tpetra "
1212  "developers.");
1213 
1214  // This is a collective operation, if it hasn't been called before.
1215  setupDirectory ();
1216  return directory_->isOneToOne (*this);
1217  }
1218 
1219 
1220  template <class LocalOrdinal, class GlobalOrdinal, class Node>
1221  LocalOrdinal
1223  getLocalElement (GlobalOrdinal globalIndex) const
1224  {
1225  if (isContiguous ()) {
1226  if (globalIndex < getMinGlobalIndex () ||
1227  globalIndex > getMaxGlobalIndex ()) {
1228  return Tpetra::Details::OrdinalTraits<LocalOrdinal>::invalid ();
1229  }
1230  return static_cast<LocalOrdinal> (globalIndex - getMinGlobalIndex ());
1231  }
1232  else if (globalIndex >= firstContiguousGID_ &&
1233  globalIndex <= lastContiguousGID_) {
1234  return static_cast<LocalOrdinal> (globalIndex - firstContiguousGID_);
1235  }
1236  else {
1237  // If the given global index is not in the table, this returns
1238  // the same value as OrdinalTraits<LocalOrdinal>::invalid().
1239  return glMap_.get (globalIndex);
1240  }
1241  }
1242 
1243  template <class LocalOrdinal, class GlobalOrdinal, class Node>
1244  GlobalOrdinal
1246  getGlobalElement (LocalOrdinal localIndex) const
1247  {
1248  if (localIndex < getMinLocalIndex () || localIndex > getMaxLocalIndex ()) {
1249  return Tpetra::Details::OrdinalTraits<GlobalOrdinal>::invalid ();
1250  }
1251  if (isContiguous ()) {
1252  return getMinGlobalIndex () + localIndex;
1253  }
1254  else {
1255  // This is a host Kokkos::View access, with no RCP or ArrayRCP
1256  // involvement. As a result, it is thread safe.
1257  //
1258  // lgMapHost_ is a host pointer; this does NOT assume UVM.
1259  return lgMapHost_[localIndex];
1260  }
1261  }
1262 
1263  template <class LocalOrdinal, class GlobalOrdinal, class Node>
1264  bool
1266  isNodeLocalElement (LocalOrdinal localIndex) const
1267  {
1268  if (localIndex < getMinLocalIndex () || localIndex > getMaxLocalIndex ()) {
1269  return false;
1270  } else {
1271  return true;
1272  }
1273  }
1274 
1275  template <class LocalOrdinal, class GlobalOrdinal, class Node>
1276  bool
1278  isNodeGlobalElement (GlobalOrdinal globalIndex) const {
1279  return this->getLocalElement (globalIndex) !=
1280  Tpetra::Details::OrdinalTraits<LocalOrdinal>::invalid ();
1281  }
1282 
1283  template <class LocalOrdinal, class GlobalOrdinal, class Node>
1285  return uniform_;
1286  }
1287 
1288  template <class LocalOrdinal, class GlobalOrdinal, class Node>
1290  return contiguous_;
1291  }
1292 
1293 
1294  template <class LocalOrdinal, class GlobalOrdinal, class Node>
1297  getLocalMap () const
1298  {
1299  return local_map_type (glMap_, lgMap_, getIndexBase (),
1300  getMinGlobalIndex (), getMaxGlobalIndex (),
1301  firstContiguousGID_, lastContiguousGID_,
1302  getNodeNumElements (), isContiguous ());
1303  }
1304 
1305  template <class LocalOrdinal, class GlobalOrdinal, class Node>
1306  bool
1309  {
1310  using Teuchos::outArg;
1311  using Teuchos::REDUCE_MIN;
1312  using Teuchos::reduceAll;
1313  //
1314  // Tests that avoid the Boolean all-reduce below by using
1315  // globally consistent quantities.
1316  //
1317  if (this == &map) {
1318  // Pointer equality on one process always implies pointer
1319  // equality on all processes, since Map is immutable.
1320  return true;
1321  }
1322  else if (getComm ()->getSize () != map.getComm ()->getSize ()) {
1323  // The two communicators have different numbers of processes.
1324  // It's not correct to call isCompatible() in that case. This
1325  // may result in the all-reduce hanging below.
1326  return false;
1327  }
1328  else if (getGlobalNumElements () != map.getGlobalNumElements ()) {
1329  // Two Maps are definitely NOT compatible if they have different
1330  // global numbers of indices.
1331  return false;
1332  }
1333  else if (isContiguous () && isUniform () &&
1334  map.isContiguous () && map.isUniform ()) {
1335  // Contiguous uniform Maps with the same number of processes in
1336  // their communicators, and with the same global numbers of
1337  // indices, are always compatible.
1338  return true;
1339  }
1340  else if (! isContiguous () && ! map.isContiguous () &&
1341  lgMap_.extent (0) != 0 && map.lgMap_.extent (0) != 0 &&
1342  lgMap_.data () == map.lgMap_.data ()) {
1343  // Noncontiguous Maps whose global index lists are nonempty and
1344  // have the same pointer must be the same (and therefore
1345  // contiguous).
1346  //
1347  // Nonempty is important. For example, consider a communicator
1348  // with two processes, and two Maps that share this
1349  // communicator, with zero global indices on the first process,
1350  // and different nonzero numbers of global indices on the second
1351  // process. In that case, on the first process, the pointers
1352  // would both be NULL.
1353  return true;
1354  }
1355 
1356  TEUCHOS_TEST_FOR_EXCEPTION(
1357  getGlobalNumElements () != map.getGlobalNumElements (), std::logic_error,
1358  "Tpetra::Map::isCompatible: There's a bug in this method. We've already "
1359  "checked that this condition is true above, but it's false here. "
1360  "Please report this bug to the Tpetra developers.");
1361 
1362  // Do both Maps have the same number of indices on each process?
1363  const int locallyCompat =
1364  (getNodeNumElements () == map.getNodeNumElements ()) ? 1 : 0;
1365 
1366  int globallyCompat = 0;
1367  reduceAll<int, int> (*comm_, REDUCE_MIN, locallyCompat, outArg (globallyCompat));
1368  return (globallyCompat == 1);
1369  }
1370 
1371  template <class LocalOrdinal, class GlobalOrdinal, class Node>
1372  bool
1375  {
1376  using Teuchos::ArrayView;
1377  typedef GlobalOrdinal GO;
1378  typedef typename ArrayView<const GO>::size_type size_type;
1379 
1380  // If both Maps are contiguous, we can compare their GID ranges
1381  // easily by looking at the min and max GID on this process.
1382  // Otherwise, we'll compare their GID lists. If only one Map is
1383  // contiguous, then we only have to call getNodeElementList() on
1384  // the noncontiguous Map. (It's best to avoid calling it on a
1385  // contiguous Map, since it results in unnecessary storage that
1386  // persists for the lifetime of the Map.)
1387 
1388  if (this == &map) {
1389  // Pointer equality on one process always implies pointer
1390  // equality on all processes, since Map is immutable.
1391  return true;
1392  }
1393  else if (getNodeNumElements () != map.getNodeNumElements ()) {
1394  return false;
1395  }
1396  else if (getMinGlobalIndex () != map.getMinGlobalIndex () ||
1397  getMaxGlobalIndex () != map.getMaxGlobalIndex ()) {
1398  return false;
1399  }
1400  else {
1401  if (isContiguous ()) {
1402  if (map.isContiguous ()) {
1403  return true; // min and max match, so the ranges match.
1404  }
1405  else { // *this is contiguous, but map is not contiguous
1406  TEUCHOS_TEST_FOR_EXCEPTION(
1407  ! this->isContiguous () || map.isContiguous (), std::logic_error,
1408  "Tpetra::Map::locallySameAs: BUG");
1409  ArrayView<const GO> rhsElts = map.getNodeElementList ();
1410  const GO minLhsGid = this->getMinGlobalIndex ();
1411  const size_type numRhsElts = rhsElts.size ();
1412  for (size_type k = 0; k < numRhsElts; ++k) {
1413  const GO curLhsGid = minLhsGid + static_cast<GO> (k);
1414  if (curLhsGid != rhsElts[k]) {
1415  return false; // stop on first mismatch
1416  }
1417  }
1418  return true;
1419  }
1420  }
1421  else if (map.isContiguous ()) { // *this is not contiguous, but map is
1422  TEUCHOS_TEST_FOR_EXCEPTION(
1423  this->isContiguous () || ! map.isContiguous (), std::logic_error,
1424  "Tpetra::Map::locallySameAs: BUG");
1425  ArrayView<const GO> lhsElts = this->getNodeElementList ();
1426  const GO minRhsGid = map.getMinGlobalIndex ();
1427  const size_type numLhsElts = lhsElts.size ();
1428  for (size_type k = 0; k < numLhsElts; ++k) {
1429  const GO curRhsGid = minRhsGid + static_cast<GO> (k);
1430  if (curRhsGid != lhsElts[k]) {
1431  return false; // stop on first mismatch
1432  }
1433  }
1434  return true;
1435  }
1436  else if (this->lgMap_.data () == map.lgMap_.data ()) {
1437  // Pointers to LID->GID "map" (actually just an array) are the
1438  // same, and the number of GIDs are the same.
1439  return this->getNodeNumElements () == map.getNodeNumElements ();
1440  }
1441  else { // we actually have to compare the GIDs
1442  if (this->getNodeNumElements () != map.getNodeNumElements ()) {
1443  return false; // We already checked above, but check just in case
1444  }
1445  else {
1446  ArrayView<const GO> lhsElts = getNodeElementList ();
1447  ArrayView<const GO> rhsElts = map.getNodeElementList ();
1448 
1449  // std::equal requires that the latter range is as large as
1450  // the former. We know the ranges have equal length, because
1451  // they have the same number of local entries.
1452  return std::equal (lhsElts.begin (), lhsElts.end (), rhsElts.begin ());
1453  }
1454  }
1455  }
1456  }
1457 
1458  template <class LocalOrdinal,class GlobalOrdinal, class Node>
1459  bool
1462  {
1463  if (this == &map)
1464  return true;
1465 
1466  // We are going to check if lmap1 is fitted into lmap2
1467  auto lmap1 = map.getLocalMap();
1468  auto lmap2 = this->getLocalMap();
1469 
1470  auto numLocalElements1 = lmap1.getNodeNumElements();
1471  auto numLocalElements2 = lmap2.getNodeNumElements();
1472 
1473  if (numLocalElements1 > numLocalElements2) {
1474  // There are more indices in the first map on this process than in second map.
1475  return false;
1476  }
1477 
1478  if (lmap1.isContiguous () && lmap2.isContiguous ()) {
1479  // When both Maps are contiguous, just check the interval inclusion.
1480  return ((lmap1.getMinGlobalIndex () == lmap2.getMinGlobalIndex ()) &&
1481  (lmap1.getMaxGlobalIndex () <= lmap2.getMaxGlobalIndex ()));
1482  }
1483 
1484  if (lmap1.getMinGlobalIndex () < lmap2.getMinGlobalIndex () ||
1485  lmap1.getMaxGlobalIndex () > lmap2.getMaxGlobalIndex ()) {
1486  // The second map does not include the first map bounds, and thus some of
1487  // the first map global indices are not in the second map.
1488  return false;
1489  }
1490 
1491  typedef Kokkos::RangePolicy<LocalOrdinal, typename Node::execution_space> range_type;
1492 
1493  // Check all elements.
1494  LocalOrdinal numDiff = 0;
1495  Kokkos::parallel_reduce("isLocallyFitted", range_type(0, numLocalElements1),
1496  KOKKOS_LAMBDA(const LocalOrdinal i, LocalOrdinal& diff) {
1497  diff += (lmap1.getGlobalElement(i) != lmap2.getGlobalElement(i));
1498  }, numDiff);
1499 
1500  return (numDiff == 0);
1501  }
1502 
1503  template <class LocalOrdinal, class GlobalOrdinal, class Node>
1504  bool
1507  {
1508  using Teuchos::outArg;
1509  using Teuchos::REDUCE_MIN;
1510  using Teuchos::reduceAll;
1511  //
1512  // Tests that avoid the Boolean all-reduce below by using
1513  // globally consistent quantities.
1514  //
1515  if (this == &map) {
1516  // Pointer equality on one process always implies pointer
1517  // equality on all processes, since Map is immutable.
1518  return true;
1519  }
1520  else if (getComm ()->getSize () != map.getComm ()->getSize ()) {
1521  // The two communicators have different numbers of processes.
1522  // It's not correct to call isSameAs() in that case. This
1523  // may result in the all-reduce hanging below.
1524  return false;
1525  }
1526  else if (getGlobalNumElements () != map.getGlobalNumElements ()) {
1527  // Two Maps are definitely NOT the same if they have different
1528  // global numbers of indices.
1529  return false;
1530  }
1531  else if (getMinAllGlobalIndex () != map.getMinAllGlobalIndex () ||
1532  getMaxAllGlobalIndex () != map.getMaxAllGlobalIndex () ||
1533  getIndexBase () != map.getIndexBase ()) {
1534  // If the global min or max global index doesn't match, or if
1535  // the index base doesn't match, then the Maps aren't the same.
1536  return false;
1537  }
1538  else if (isDistributed () != map.isDistributed ()) {
1539  // One Map is distributed and the other is not, which means that
1540  // the Maps aren't the same.
1541  return false;
1542  }
1543  else if (isContiguous () && isUniform () &&
1544  map.isContiguous () && map.isUniform ()) {
1545  // Contiguous uniform Maps with the same number of processes in
1546  // their communicators, with the same global numbers of indices,
1547  // and with matching index bases and ranges, must be the same.
1548  return true;
1549  }
1550 
1551  // The two communicators must have the same number of processes,
1552  // with process ranks occurring in the same order. This uses
1553  // MPI_COMM_COMPARE. The MPI 3.1 standard (Section 6.4) says:
1554  // "Operations that access communicators are local and their
1555  // execution does not require interprocess communication."
1556  // However, just to be sure, I'll put this call after the above
1557  // tests that don't communicate.
1558  if (! ::Tpetra::Details::congruent (*comm_, * (map.getComm ()))) {
1559  return false;
1560  }
1561 
1562  // If we get this far, we need to check local properties and then
1563  // communicate local sameness across all processes.
1564  const int isSame_lcl = locallySameAs (map) ? 1 : 0;
1565 
1566  // Return true if and only if all processes report local sameness.
1567  int isSame_gbl = 0;
1568  reduceAll<int, int> (*comm_, REDUCE_MIN, isSame_lcl, outArg (isSame_gbl));
1569  return isSame_gbl == 1;
1570  }
1571 
1572  namespace { // (anonymous)
1573  template <class LO, class GO, class DT>
1574  class FillLgMap {
1575  public:
1576  FillLgMap (const Kokkos::View<GO*, DT>& lgMap,
1577  const GO startGid) :
1578  lgMap_ (lgMap), startGid_ (startGid)
1579  {
1580  Kokkos::RangePolicy<LO, typename DT::execution_space>
1581  range (static_cast<LO> (0), static_cast<LO> (lgMap.size ()));
1582  Kokkos::parallel_for (range, *this);
1583  }
1584 
1585  KOKKOS_INLINE_FUNCTION void operator () (const LO& lid) const {
1586  lgMap_(lid) = startGid_ + static_cast<GO> (lid);
1587  }
1588 
1589  private:
1590  const Kokkos::View<GO*, DT> lgMap_;
1591  const GO startGid_;
1592  };
1593 
1594  } // namespace (anonymous)
1595 
1596 
1597  template <class LocalOrdinal, class GlobalOrdinal, class Node>
1598  typename Map<LocalOrdinal,GlobalOrdinal,Node>::global_indices_array_type
1600  {
1601  typedef LocalOrdinal LO;
1602  typedef GlobalOrdinal GO;
1603  typedef device_type DT;
1604 
1605  typedef decltype (lgMap_) const_lg_view_type;
1606  typedef typename const_lg_view_type::non_const_type lg_view_type;
1607 
1608  // If the local-to-global mapping doesn't exist yet, and if we
1609  // have local entries, then create and fill the local-to-global
1610  // mapping.
1611  const bool needToCreateLocalToGlobalMapping =
1612  lgMap_.extent (0) == 0 && numLocalElements_ > 0;
1613 
1614  if (needToCreateLocalToGlobalMapping) {
1615 #ifdef HAVE_TEUCHOS_DEBUG
1616  // The local-to-global mapping should have been set up already
1617  // for a noncontiguous map.
1618  TEUCHOS_TEST_FOR_EXCEPTION( ! isContiguous(), std::logic_error,
1619  "Tpetra::Map::getNodeElementList: The local-to-global mapping (lgMap_) "
1620  "should have been set up already for a noncontiguous Map. Please report"
1621  " this bug to the Tpetra team.");
1622 #endif // HAVE_TEUCHOS_DEBUG
1623 
1624  const LO numElts = static_cast<LO> (getNodeNumElements ());
1625 
1626  using Kokkos::view_alloc;
1627  using Kokkos::WithoutInitializing;
1628  lg_view_type lgMap ("lgMap", numElts);
1629  FillLgMap<LO, GO, DT> fillIt (lgMap, minMyGID_);
1630 
1631  auto lgMapHost =
1632  Kokkos::create_mirror_view (Kokkos::HostSpace (), lgMap);
1633  Kokkos::deep_copy (lgMapHost, lgMap);
1634 
1635  // "Commit" the local-to-global lookup table we filled in above.
1636  lgMap_ = lgMap;
1637  lgMapHost_ = lgMapHost;
1638 
1639  // lgMapHost_ may be a UVM View, so insert a fence to ensure
1640  // coherent host access. We only need to do this once, because
1641  // lgMapHost_ is immutable after initialization.
1642  execution_space().fence ();
1643  }
1644 
1645  return lgMap_;
1646  }
1647 
1648  template <class LocalOrdinal, class GlobalOrdinal, class Node>
1649  Teuchos::ArrayView<const GlobalOrdinal>
1651  {
1652  typedef GlobalOrdinal GO; // convenient abbreviation
1653 
1654  // If the local-to-global mapping doesn't exist yet, and if we
1655  // have local entries, then create and fill the local-to-global
1656  // mapping.
1657  (void) this->getMyGlobalIndices ();
1658 
1659  // This does NOT assume UVM; lgMapHost_ is a host pointer.
1660  const GO* lgMapHostRawPtr = lgMapHost_.data ();
1661  // The third argument forces ArrayView not to try to track memory
1662  // in a debug build. We have to use it because the memory does
1663  // not belong to a Teuchos memory management class.
1664  return Teuchos::ArrayView<const GO> (lgMapHostRawPtr,
1665  lgMapHost_.extent (0),
1666  Teuchos::RCP_DISABLE_NODE_LOOKUP);
1667  }
1668 
1669  template <class LocalOrdinal, class GlobalOrdinal, class Node>
1671  return distributed_;
1672  }
1673 
1674  template <class LocalOrdinal, class GlobalOrdinal, class Node>
1676  using Teuchos::TypeNameTraits;
1677  std::ostringstream os;
1678 
1679  os << "Tpetra::Map: {"
1680  << "LocalOrdinalType: " << TypeNameTraits<LocalOrdinal>::name ()
1681  << ", GlobalOrdinalType: " << TypeNameTraits<GlobalOrdinal>::name ()
1682  << ", NodeType: " << TypeNameTraits<Node>::name ();
1683  if (this->getObjectLabel () != "") {
1684  os << ", Label: \"" << this->getObjectLabel () << "\"";
1685  }
1686  os << ", Global number of entries: " << getGlobalNumElements ()
1687  << ", Number of processes: " << getComm ()->getSize ()
1688  << ", Uniform: " << (isUniform () ? "true" : "false")
1689  << ", Contiguous: " << (isContiguous () ? "true" : "false")
1690  << ", Distributed: " << (isDistributed () ? "true" : "false")
1691  << "}";
1692  return os.str ();
1693  }
1694 
1699  template <class LocalOrdinal, class GlobalOrdinal, class Node>
1700  std::string
1702  localDescribeToString (const Teuchos::EVerbosityLevel vl) const
1703  {
1704  typedef LocalOrdinal LO;
1705  using std::endl;
1706 
1707  // This preserves current behavior of Map.
1708  if (vl < Teuchos::VERB_HIGH) {
1709  return std::string ();
1710  }
1711  auto outStringP = Teuchos::rcp (new std::ostringstream ());
1712  Teuchos::RCP<Teuchos::FancyOStream> outp =
1713  Teuchos::getFancyOStream (outStringP);
1714  Teuchos::FancyOStream& out = *outp;
1715 
1716  auto comm = this->getComm ();
1717  const int myRank = comm->getRank ();
1718  const int numProcs = comm->getSize ();
1719  out << "Process " << myRank << " of " << numProcs << ":" << endl;
1720  Teuchos::OSTab tab1 (out);
1721 
1722  const LO numEnt = static_cast<LO> (this->getNodeNumElements ());
1723  out << "My number of entries: " << numEnt << endl
1724  << "My minimum global index: " << this->getMinGlobalIndex () << endl
1725  << "My maximum global index: " << this->getMaxGlobalIndex () << endl;
1726 
1727  if (vl == Teuchos::VERB_EXTREME) {
1728  out << "My global indices: [";
1729  const LO minLclInd = this->getMinLocalIndex ();
1730  for (LO k = 0; k < numEnt; ++k) {
1731  out << minLclInd + this->getGlobalElement (k);
1732  if (k + 1 < numEnt) {
1733  out << ", ";
1734  }
1735  }
1736  out << "]" << endl;
1737  }
1738 
1739  out.flush (); // make sure the ostringstream got everything
1740  return outStringP->str ();
1741  }
1742 
1743  template <class LocalOrdinal, class GlobalOrdinal, class Node>
1744  void
1746  describe (Teuchos::FancyOStream &out,
1747  const Teuchos::EVerbosityLevel verbLevel) const
1748  {
1749  using Teuchos::TypeNameTraits;
1750  using Teuchos::VERB_DEFAULT;
1751  using Teuchos::VERB_NONE;
1752  using Teuchos::VERB_LOW;
1753  using Teuchos::VERB_HIGH;
1754  using std::endl;
1755  typedef LocalOrdinal LO;
1756  typedef GlobalOrdinal GO;
1757  const Teuchos::EVerbosityLevel vl =
1758  (verbLevel == VERB_DEFAULT) ? VERB_LOW : verbLevel;
1759 
1760  if (vl == VERB_NONE) {
1761  return; // don't print anything
1762  }
1763  // If this Map's Comm is null, then the Map does not participate
1764  // in collective operations with the other processes. In that
1765  // case, it is not even legal to call this method. The reasonable
1766  // thing to do in that case is nothing.
1767  auto comm = this->getComm ();
1768  if (comm.is_null ()) {
1769  return;
1770  }
1771  const int myRank = comm->getRank ();
1772  const int numProcs = comm->getSize ();
1773 
1774  // Only Process 0 should touch the output stream, but this method
1775  // in general may need to do communication. Thus, we may need to
1776  // preserve the current tab level across multiple "if (myRank ==
1777  // 0) { ... }" inner scopes. This is why we sometimes create
1778  // OSTab instances by pointer, instead of by value. We only need
1779  // to create them by pointer if the tab level must persist through
1780  // multiple inner scopes.
1781  Teuchos::RCP<Teuchos::OSTab> tab0, tab1;
1782 
1783  if (myRank == 0) {
1784  // At every verbosity level but VERB_NONE, Process 0 prints.
1785  // By convention, describe() always begins with a tab before
1786  // printing.
1787  tab0 = Teuchos::rcp (new Teuchos::OSTab (out));
1788  out << "\"Tpetra::Map\":" << endl;
1789  tab1 = Teuchos::rcp (new Teuchos::OSTab (out));
1790  {
1791  out << "Template parameters:" << endl;
1792  Teuchos::OSTab tab2 (out);
1793  out << "LocalOrdinal: " << TypeNameTraits<LO>::name () << endl
1794  << "GlobalOrdinal: " << TypeNameTraits<GO>::name () << endl
1795  << "Node: " << TypeNameTraits<Node>::name () << endl;
1796  }
1797  const std::string label = this->getObjectLabel ();
1798  if (label != "") {
1799  out << "Label: \"" << label << "\"" << endl;
1800  }
1801  out << "Global number of entries: " << getGlobalNumElements () << endl
1802  << "Minimum global index: " << getMinAllGlobalIndex () << endl
1803  << "Maximum global index: " << getMaxAllGlobalIndex () << endl
1804  << "Index base: " << getIndexBase () << endl
1805  << "Number of processes: " << numProcs << endl
1806  << "Uniform: " << (isUniform () ? "true" : "false") << endl
1807  << "Contiguous: " << (isContiguous () ? "true" : "false") << endl
1808  << "Distributed: " << (isDistributed () ? "true" : "false") << endl;
1809  }
1810 
1811  // This is collective over the Map's communicator.
1812  if (vl >= VERB_HIGH) { // VERB_HIGH or VERB_EXTREME
1813  const std::string lclStr = this->localDescribeToString (vl);
1814  Tpetra::Details::gathervPrint (out, lclStr, *comm);
1815  }
1816  }
1817 
1818  template <class LocalOrdinal, class GlobalOrdinal, class Node>
1819  Teuchos::RCP<const Map<LocalOrdinal, GlobalOrdinal, Node> >
1821  replaceCommWithSubset (const Teuchos::RCP<const Teuchos::Comm<int> >& newComm) const
1822  {
1823  using Teuchos::RCP;
1824  using Teuchos::rcp;
1825  typedef global_size_t GST;
1826  typedef LocalOrdinal LO;
1827  typedef GlobalOrdinal GO;
1828  typedef Map<LO, GO, Node> map_type;
1829 
1830  // mfh 26 Mar 2013: The lazy way to do this is simply to recreate
1831  // the Map by calling its ordinary public constructor, using the
1832  // original Map's data. This only involves O(1) all-reduces over
1833  // the new communicator, which in the common case only includes a
1834  // small number of processes.
1835 
1836  // Create the Map to return.
1837  if (newComm.is_null () || newComm->getSize () < 1) {
1838  return Teuchos::null; // my process does not participate in the new Map
1839  }
1840  else if (newComm->getSize () == 1) {
1841  // The case where the new communicator has only one process is
1842  // easy. We don't have to communicate to get all the
1843  // information we need. Use the default comm to create the new
1844  // Map, then fill in all the fields directly.
1845  RCP<map_type> newMap (new map_type ());
1846 
1847  newMap->comm_ = newComm;
1848  // mfh 07 Oct 2016: Preserve original behavior, even though the
1849  // original index base may no longer be the globally min global
1850  // index. See #616 for why this doesn't matter so much anymore.
1851  newMap->indexBase_ = this->indexBase_;
1852  newMap->numGlobalElements_ = this->numLocalElements_;
1853  newMap->numLocalElements_ = this->numLocalElements_;
1854  newMap->minMyGID_ = this->minMyGID_;
1855  newMap->maxMyGID_ = this->maxMyGID_;
1856  newMap->minAllGID_ = this->minMyGID_;
1857  newMap->maxAllGID_ = this->maxMyGID_;
1858  newMap->firstContiguousGID_ = this->firstContiguousGID_;
1859  newMap->lastContiguousGID_ = this->lastContiguousGID_;
1860  // Since the new communicator has only one process, neither
1861  // uniformity nor contiguity have changed.
1862  newMap->uniform_ = this->uniform_;
1863  newMap->contiguous_ = this->contiguous_;
1864  // The new communicator only has one process, so the new Map is
1865  // not distributed.
1866  newMap->distributed_ = false;
1867  newMap->lgMap_ = this->lgMap_;
1868  newMap->lgMapHost_ = this->lgMapHost_;
1869  newMap->glMap_ = this->glMap_;
1870  // It's OK not to initialize the new Map's Directory.
1871  // This is initialized lazily, on first call to getRemoteIndexList.
1872 
1873  return newMap;
1874  }
1875  else { // newComm->getSize() != 1
1876  // Even if the original Map is contiguous, the new Map might not
1877  // be, especially if the excluded processes have ranks != 0 or
1878  // newComm->getSize()-1. The common case for this method is to
1879  // exclude many (possibly even all but one) processes, so it
1880  // likely doesn't pay to do the global communication (over the
1881  // original communicator) to figure out whether we can optimize
1882  // the result Map. Thus, we just set up the result Map as
1883  // noncontiguous.
1884  //
1885  // TODO (mfh 07 Oct 2016) We don't actually need to reconstruct
1886  // the global-to-local table, etc. Optimize this code path to
1887  // avoid unnecessary local work.
1888 
1889  // Make Map (re)compute the global number of elements.
1890  const GST RECOMPUTE = Tpetra::Details::OrdinalTraits<GST>::invalid ();
1891  // TODO (mfh 07 Oct 2016) If we use any Map constructor, we have
1892  // to use the noncontiguous Map constructor, since the new Map
1893  // might not be contiguous. Even if the old Map was contiguous,
1894  // some process in the "middle" might have been excluded. If we
1895  // want to avoid local work, we either have to do the setup by
1896  // hand, or write a new Map constructor.
1897 #if 1
1898  // The disabled code here throws the following exception in
1899  // Map's replaceCommWithSubset test:
1900  //
1901  // Throw test that evaluated to true: static_cast<unsigned long long> (numKeys) > static_cast<unsigned long long> (::Kokkos::Details::ArithTraits<ValueType>::max ())
1902  // 10:
1903  // 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.
1904  // 10: Process 3: origComm->replaceCommWithSubset(subsetComm) threw an exception: /scratch/prj/Trilinos/Trilinos/packages/tpetra/core/src/Tpetra_Details_FixedHashTable_def.hpp:1044:
1905 
1906  auto lgMap = this->getMyGlobalIndices ();
1907  typedef typename std::decay<decltype (lgMap.extent (0)) >::type size_type;
1908  const size_type lclNumInds =
1909  static_cast<size_type> (this->getNodeNumElements ());
1910  using Teuchos::TypeNameTraits;
1911  TEUCHOS_TEST_FOR_EXCEPTION
1912  (lgMap.extent (0) != lclNumInds, std::logic_error,
1913  "Tpetra::Map::replaceCommWithSubset: Result of getMyGlobalIndices() "
1914  "has length " << lgMap.extent (0) << " (of type " <<
1915  TypeNameTraits<size_type>::name () << ") != this->getNodeNumElements()"
1916  " = " << this->getNodeNumElements () << ". The latter, upon being "
1917  "cast to size_type = " << TypeNameTraits<size_type>::name () << ", "
1918  "becomes " << lclNumInds << ". Please report this bug to the Tpetra "
1919  "developers.");
1920 #else
1921  Teuchos::ArrayView<const GO> lgMap = this->getNodeElementList ();
1922 #endif // 1
1923 
1924  const GO indexBase = this->getIndexBase ();
1925  return rcp (new map_type (RECOMPUTE, lgMap, indexBase, newComm));
1926  }
1927  }
1928 
1929  template <class LocalOrdinal, class GlobalOrdinal, class Node>
1930  Teuchos::RCP<const Map<LocalOrdinal, GlobalOrdinal, Node> >
1932  removeEmptyProcesses () const
1933  {
1934  using Teuchos::Comm;
1935  using Teuchos::null;
1936  using Teuchos::outArg;
1937  using Teuchos::RCP;
1938  using Teuchos::rcp;
1939  using Teuchos::REDUCE_MIN;
1940  using Teuchos::reduceAll;
1941 
1942  // Create the new communicator. split() returns a valid
1943  // communicator on all processes. On processes where color == 0,
1944  // ignore the result. Passing key == 0 tells MPI to order the
1945  // processes in the new communicator by their rank in the old
1946  // communicator.
1947  const int color = (numLocalElements_ == 0) ? 0 : 1;
1948  // MPI_Comm_split must be called collectively over the original
1949  // communicator. We can't just call it on processes with color
1950  // one, even though we will ignore its result on processes with
1951  // color zero.
1952  RCP<const Comm<int> > newComm = comm_->split (color, 0);
1953  if (color == 0) {
1954  newComm = null;
1955  }
1956 
1957  // Create the Map to return.
1958  if (newComm.is_null ()) {
1959  return null; // my process does not participate in the new Map
1960  } else {
1961  // The default constructor that's useful for clone() above is
1962  // also useful here.
1963  RCP<Map> map = rcp (new Map ());
1964 
1965  map->comm_ = newComm;
1966  map->indexBase_ = indexBase_;
1967  map->numGlobalElements_ = numGlobalElements_;
1968  map->numLocalElements_ = numLocalElements_;
1969  map->minMyGID_ = minMyGID_;
1970  map->maxMyGID_ = maxMyGID_;
1971  map->minAllGID_ = minAllGID_;
1972  map->maxAllGID_ = maxAllGID_;
1973  map->firstContiguousGID_= firstContiguousGID_;
1974  map->lastContiguousGID_ = lastContiguousGID_;
1975 
1976  // Uniformity and contiguity have not changed. The directory
1977  // has changed, but we've taken care of that above.
1978  map->uniform_ = uniform_;
1979  map->contiguous_ = contiguous_;
1980 
1981  // If the original Map was NOT distributed, then the new Map
1982  // cannot be distributed.
1983  //
1984  // If the number of processes in the new communicator is 1, then
1985  // the new Map is not distributed.
1986  //
1987  // Otherwise, we have to check the new Map using an all-reduce
1988  // (over the new communicator). For example, the original Map
1989  // may have had some processes with zero elements, and all other
1990  // processes with the same number of elements as in the whole
1991  // Map. That Map is technically distributed, because of the
1992  // processes with zero elements. Removing those processes would
1993  // make the new Map locally replicated.
1994  if (! distributed_ || newComm->getSize () == 1) {
1995  map->distributed_ = false;
1996  } else {
1997  const int iOwnAllGids = (numLocalElements_ == numGlobalElements_) ? 1 : 0;
1998  int allProcsOwnAllGids = 0;
1999  reduceAll<int, int> (*newComm, REDUCE_MIN, iOwnAllGids, outArg (allProcsOwnAllGids));
2000  map->distributed_ = (allProcsOwnAllGids == 1) ? false : true;
2001  }
2002 
2003  map->lgMap_ = lgMap_;
2004  map->lgMapHost_ = lgMapHost_;
2005  map->glMap_ = glMap_;
2006 
2007  // Map's default constructor creates an uninitialized Directory.
2008  // The Directory will be initialized on demand in
2009  // getRemoteIndexList().
2010  //
2011  // FIXME (mfh 26 Mar 2013) It should be possible to "filter" the
2012  // directory more efficiently than just recreating it. If
2013  // directory recreation proves a bottleneck, we can always
2014  // revisit this. On the other hand, Directory creation is only
2015  // collective over the new, presumably much smaller
2016  // communicator, so it may not be worth the effort to optimize.
2017 
2018  return map;
2019  }
2020  }
2021 
2022  template <class LocalOrdinal, class GlobalOrdinal, class Node>
2023  void
2025  {
2026  TEUCHOS_TEST_FOR_EXCEPTION(
2027  directory_.is_null (), std::logic_error, "Tpetra::Map::setupDirectory: "
2028  "The Directory is null. "
2029  "Please report this bug to the Tpetra developers.");
2030 
2031  // Only create the Directory if it hasn't been created yet.
2032  // This is a collective operation.
2033  if (! directory_->initialized ()) {
2034  directory_->initialize (*this);
2035  }
2036  }
2037 
2038  template <class LocalOrdinal, class GlobalOrdinal, class Node>
2039  LookupStatus
2041  getRemoteIndexList (const Teuchos::ArrayView<const GlobalOrdinal>& GIDs,
2042  const Teuchos::ArrayView<int>& PIDs,
2043  const Teuchos::ArrayView<LocalOrdinal>& LIDs) const
2044  {
2045  using Tpetra::Details::OrdinalTraits;
2046  typedef Teuchos::ArrayView<int>::size_type size_type;
2047 
2048  // Empty Maps (i.e., containing no indices on any processes in the
2049  // Map's communicator) are perfectly valid. In that case, if the
2050  // input GID list is nonempty, we fill the output arrays with
2051  // invalid values, and return IDNotPresent to notify the caller.
2052  // It's perfectly valid to give getRemoteIndexList GIDs that the
2053  // Map doesn't own. SubmapImport test 2 needs this functionality.
2054  if (getGlobalNumElements () == 0) {
2055  if (GIDs.size () == 0) {
2056  return AllIDsPresent; // trivially
2057  } else {
2058  for (size_type k = 0; k < PIDs.size (); ++k) {
2059  PIDs[k] = OrdinalTraits<int>::invalid ();
2060  }
2061  for (size_type k = 0; k < LIDs.size (); ++k) {
2062  LIDs[k] = OrdinalTraits<LocalOrdinal>::invalid ();
2063  }
2064  return IDNotPresent;
2065  }
2066  }
2067 
2068  // getRemoteIndexList must be called collectively, and Directory
2069  // initialization is collective too, so it's OK to initialize the
2070  // Directory on demand.
2071  setupDirectory ();
2072  return directory_->getDirectoryEntries (*this, GIDs, PIDs, LIDs);
2073  }
2074 
2075  template <class LocalOrdinal, class GlobalOrdinal, class Node>
2076  LookupStatus
2078  getRemoteIndexList (const Teuchos::ArrayView<const GlobalOrdinal> & GIDs,
2079  const Teuchos::ArrayView<int> & PIDs) const
2080  {
2081  if (getGlobalNumElements () == 0) {
2082  if (GIDs.size () == 0) {
2083  return AllIDsPresent; // trivially
2084  } else {
2085  // The Map contains no indices, so all output PIDs are invalid.
2086  for (Teuchos::ArrayView<int>::size_type k = 0; k < PIDs.size (); ++k) {
2087  PIDs[k] = Tpetra::Details::OrdinalTraits<int>::invalid ();
2088  }
2089  return IDNotPresent;
2090  }
2091  }
2092 
2093  // getRemoteIndexList must be called collectively, and Directory
2094  // initialization is collective too, so it's OK to initialize the
2095  // Directory on demand.
2096  setupDirectory ();
2097  return directory_->getDirectoryEntries (*this, GIDs, PIDs);
2098  }
2099 
2100  template <class LocalOrdinal, class GlobalOrdinal, class Node>
2101  Teuchos::RCP<const Teuchos::Comm<int> >
2103  return comm_;
2104  }
2105 
2106 #ifdef TPETRA_ENABLE_DEPRECATED_CODE
2107  template <class LocalOrdinal, class GlobalOrdinal, class Node>
2108  TPETRA_DEPRECATED
2109  Teuchos::RCP<Node>
2111  // Node instances don't do anything any more, but sometimes it
2112  // helps for them to be nonnull.
2113  return Teuchos::rcp (new Node);
2114  }
2115 #endif // TPETRA_ENABLE_DEPRECATED_CODE
2116 
2117  template <class LocalOrdinal,class GlobalOrdinal, class Node>
2118  bool Map<LocalOrdinal,GlobalOrdinal,Node>::checkIsDist() const {
2119  using Teuchos::as;
2120  using Teuchos::outArg;
2121  using Teuchos::REDUCE_MIN;
2122  using Teuchos::reduceAll;
2123 
2124  bool global = false;
2125  if (comm_->getSize () > 1) {
2126  // The communicator has more than one process, but that doesn't
2127  // necessarily mean the Map is distributed.
2128  int localRep = 0;
2129  if (numGlobalElements_ == as<global_size_t> (numLocalElements_)) {
2130  // The number of local elements on this process equals the
2131  // number of global elements.
2132  //
2133  // NOTE (mfh 22 Nov 2011) Does this still work if there were
2134  // duplicates in the global ID list on input (the third Map
2135  // constructor), so that the number of local elements (which
2136  // are not duplicated) on this process could be less than the
2137  // number of global elements, even if this process owns all
2138  // the elements?
2139  localRep = 1;
2140  }
2141  int allLocalRep;
2142  reduceAll<int, int> (*comm_, REDUCE_MIN, localRep, outArg (allLocalRep));
2143  if (allLocalRep != 1) {
2144  // At least one process does not own all the elements.
2145  // This makes the Map a distributed Map.
2146  global = true;
2147  }
2148  }
2149  // If the communicator has only one process, then the Map is not
2150  // distributed.
2151  return global;
2152  }
2153 
2154 } // namespace Tpetra
2155 
2156 template <class LocalOrdinal, class GlobalOrdinal>
2157 Teuchos::RCP< const Tpetra::Map<LocalOrdinal,GlobalOrdinal> >
2158 Tpetra::createLocalMap (const size_t numElements,
2159  const Teuchos::RCP<const Teuchos::Comm<int> >& comm)
2160 {
2161  typedef LocalOrdinal LO;
2162  typedef GlobalOrdinal GO;
2163  typedef typename ::Tpetra::Map<LO, GO>::node_type NT;
2164  return createLocalMapWithNode<LO, GO, NT> (numElements, comm);
2165 }
2166 
2167 template <class LocalOrdinal, class GlobalOrdinal>
2168 Teuchos::RCP< const Tpetra::Map<LocalOrdinal,GlobalOrdinal> >
2169 Tpetra::createUniformContigMap (const global_size_t numElements,
2170  const Teuchos::RCP<const Teuchos::Comm<int> >& comm)
2171 {
2172  typedef LocalOrdinal LO;
2173  typedef GlobalOrdinal GO;
2174  typedef typename ::Tpetra::Map<LO, GO>::node_type NT;
2175  return createUniformContigMapWithNode<LO, GO, NT> (numElements, comm);
2176 }
2177 
2178 #ifdef TPETRA_ENABLE_DEPRECATED_CODE
2179 template <class LocalOrdinal, class GlobalOrdinal, class Node>
2180 TPETRA_DEPRECATED
2181 Teuchos::RCP< const Tpetra::Map<LocalOrdinal,GlobalOrdinal,Node> >
2182 Tpetra::createUniformContigMapWithNode (const global_size_t numElements,
2183  const Teuchos::RCP<const Teuchos::Comm<int> >& comm,
2184  const Teuchos::RCP<Node>& /* node */
2185 )
2186 {
2187  return Tpetra::createUniformContigMapWithNode<LocalOrdinal,GlobalOrdinal,Node>
2188  (numElements, comm);
2189 }
2190 #endif // TPETRA_ENABLE_DEPRECATED_CODE
2191 
2192 template <class LocalOrdinal, class GlobalOrdinal, class Node>
2193 Teuchos::RCP< const Tpetra::Map<LocalOrdinal,GlobalOrdinal,Node> >
2194 Tpetra::createUniformContigMapWithNode (const global_size_t numElements,
2195  const Teuchos::RCP<const Teuchos::Comm<int> >& comm
2196 )
2197 {
2198  using Teuchos::rcp;
2200  const GlobalOrdinal indexBase = static_cast<GlobalOrdinal> (0);
2201 
2202  return rcp (new map_type (numElements, indexBase, comm, GloballyDistributed));
2203 }
2204 
2205 #ifdef TPETRA_ENABLE_DEPRECATED_CODE
2206 template <class LocalOrdinal, class GlobalOrdinal, class Node>
2207 TPETRA_DEPRECATED
2208 Teuchos::RCP< const Tpetra::Map<LocalOrdinal,GlobalOrdinal,Node> >
2209 Tpetra::createLocalMapWithNode (const size_t numElements,
2210  const Teuchos::RCP<const Teuchos::Comm<int> >& comm,
2211  const Teuchos::RCP<Node>& /* node */
2212 )
2213 {
2214  return Tpetra::createLocalMapWithNode<LocalOrdinal,GlobalOrdinal,Node>
2215  (numElements, comm);
2216 }
2217 #endif // TPETRA_ENABLE_DEPRECATED_CODE
2218 
2219 template <class LocalOrdinal, class GlobalOrdinal, class Node>
2220 Teuchos::RCP< const Tpetra::Map<LocalOrdinal,GlobalOrdinal,Node> >
2221 Tpetra::createLocalMapWithNode (const size_t numElements,
2222  const Teuchos::RCP<const Teuchos::Comm<int> >& comm
2223 )
2224 {
2225  using Tpetra::global_size_t;
2226  using Teuchos::rcp;
2228  const GlobalOrdinal indexBase = static_cast<GlobalOrdinal> (0);
2229  const global_size_t globalNumElts = static_cast<global_size_t> (numElements);
2230 
2231  return rcp (new map_type (globalNumElts, indexBase, comm, LocallyReplicated));
2232 }
2233 
2234 #ifdef TPETRA_ENABLE_DEPRECATED_CODE
2235 template <class LocalOrdinal, class GlobalOrdinal, class Node>
2236 TPETRA_DEPRECATED
2237 Teuchos::RCP< const Tpetra::Map<LocalOrdinal,GlobalOrdinal,Node> >
2239  const size_t localNumElements,
2240  const Teuchos::RCP<const Teuchos::Comm<int> >& comm,
2241  const Teuchos::RCP<Node>& /* node */
2242 )
2243 {
2244  return Tpetra::createContigMapWithNode<LocalOrdinal,GlobalOrdinal,Node>
2245  (numElements, localNumElements, comm);
2246 }
2247 #endif // TPETRA_ENABLE_DEPRECATED_CODE
2248 
2249 template <class LocalOrdinal, class GlobalOrdinal, class Node>
2250 Teuchos::RCP< const Tpetra::Map<LocalOrdinal,GlobalOrdinal,Node> >
2252  const size_t localNumElements,
2253  const Teuchos::RCP<const Teuchos::Comm<int> >& comm
2254 )
2255 {
2256  using Teuchos::rcp;
2258  const GlobalOrdinal indexBase = static_cast<GlobalOrdinal> (0);
2259 
2260  return rcp (new map_type (numElements, localNumElements, indexBase, comm));
2261 }
2262 
2263 template <class LocalOrdinal, class GlobalOrdinal>
2264 Teuchos::RCP< const Tpetra::Map<LocalOrdinal,GlobalOrdinal> >
2266  const size_t localNumElements,
2267  const Teuchos::RCP<const Teuchos::Comm<int> >& comm)
2268 {
2269  typedef LocalOrdinal LO;
2270  typedef GlobalOrdinal GO;
2272 
2273  return Tpetra::createContigMapWithNode<LO, GO, NT> (numElements, localNumElements, comm);
2274 }
2275 
2276 
2277 template <class LocalOrdinal, class GlobalOrdinal>
2278 Teuchos::RCP< const Tpetra::Map<LocalOrdinal,GlobalOrdinal> >
2279 Tpetra::createNonContigMap(const Teuchos::ArrayView<const GlobalOrdinal>& elementList,
2280  const Teuchos::RCP<const Teuchos::Comm<int> >& comm)
2281 {
2282  typedef LocalOrdinal LO;
2283  typedef GlobalOrdinal GO;
2285 
2286  return Tpetra::createNonContigMapWithNode<LO, GO, NT> (elementList, comm);
2287 }
2288 
2289 
2290 #ifdef TPETRA_ENABLE_DEPRECATED_CODE
2291 template <class LocalOrdinal, class GlobalOrdinal, class Node>
2292 TPETRA_DEPRECATED
2293 Teuchos::RCP< const Tpetra::Map<LocalOrdinal,GlobalOrdinal,Node> >
2294 Tpetra::createNonContigMapWithNode (const Teuchos::ArrayView<const GlobalOrdinal>& elementList,
2295  const Teuchos::RCP<const Teuchos::Comm<int> >& comm,
2296  const Teuchos::RCP<Node>& /* node */
2297 )
2298 {
2299  return Tpetra::createNonContigMapWithNode<LocalOrdinal,GlobalOrdinal,Node>
2300  (elementList, comm);
2301 }
2302 #endif // TPETRA_ENABLE_DEPRECATED_CODE
2303 
2304 template <class LocalOrdinal, class GlobalOrdinal, class Node>
2305 Teuchos::RCP< const Tpetra::Map<LocalOrdinal,GlobalOrdinal,Node> >
2306 Tpetra::createNonContigMapWithNode (const Teuchos::ArrayView<const GlobalOrdinal>& elementList,
2307  const Teuchos::RCP<const Teuchos::Comm<int> >& comm
2308 )
2309 {
2310  using Teuchos::rcp;
2312  using GST = Tpetra::global_size_t;
2313  const GST INV = Tpetra::Details::OrdinalTraits<GST>::invalid ();
2314  // FIXME (mfh 22 Jul 2016) This is what I found here, but maybe this
2315  // shouldn't be zero, given that the index base is supposed to equal
2316  // the globally min global index?
2317  const GlobalOrdinal indexBase = 0;
2318 
2319  return rcp (new map_type (INV, elementList, indexBase, comm));
2320 }
2321 
2322 #ifdef TPETRA_ENABLE_DEPRECATED_CODE
2323 template <class LocalOrdinal, class GlobalOrdinal, class Node>
2324 TPETRA_DEPRECATED
2325 Teuchos::RCP< const Tpetra::Map<LocalOrdinal,GlobalOrdinal,Node> >
2326 Tpetra::createWeightedContigMapWithNode (const int myWeight,
2327  const Tpetra::global_size_t numElements,
2328  const Teuchos::RCP<const Teuchos::Comm<int> >& comm,
2329  const Teuchos::RCP<Node>& /* node */
2330 )
2331 {
2332  Teuchos::RCP< Tpetra::Map<LocalOrdinal,GlobalOrdinal,Node> > map;
2333  int sumOfWeights, elemsLeft, localNumElements;
2334  const int numImages = comm->getSize();
2335  const int myImageID = comm->getRank();
2336  Teuchos::reduceAll<int>(*comm,Teuchos::REDUCE_SUM,myWeight,Teuchos::outArg(sumOfWeights));
2337  const double myShare = ((double)myWeight) / ((double)sumOfWeights);
2338  localNumElements = (int)std::floor( myShare * ((double)numElements) );
2339  // std::cout << "numElements: " << numElements << " myWeight: " << myWeight << " sumOfWeights: " << sumOfWeights << " myShare: " << myShare << std::endl;
2340  Teuchos::reduceAll<int>(*comm,Teuchos::REDUCE_SUM,localNumElements,Teuchos::outArg(elemsLeft));
2341  elemsLeft = numElements - elemsLeft;
2342  // std::cout << "(before) localNumElements: " << localNumElements << " elemsLeft: " << elemsLeft << std::endl;
2343  // i think this is true. just test it for now.
2344  TEUCHOS_TEST_FOR_EXCEPT(elemsLeft < -numImages || numImages < elemsLeft);
2345  if (elemsLeft < 0) {
2346  // last elemsLeft nodes lose an element
2347  if (myImageID >= numImages-elemsLeft) --localNumElements;
2348  }
2349  else if (elemsLeft > 0) {
2350  // first elemsLeft nodes gain an element
2351  if (myImageID < elemsLeft) ++localNumElements;
2352  }
2353  // std::cout << "(after) localNumElements: " << localNumElements << std::endl;
2354  return createContigMapWithNode<LocalOrdinal,GlobalOrdinal,Node>(numElements,localNumElements,comm);
2355 }
2356 #endif // TPETRA_ENABLE_DEPRECATED_CODE
2357 
2358 
2359 template<class LO, class GO, class NT>
2360 Teuchos::RCP<const Tpetra::Map<LO, GO, NT> >
2361 Tpetra::createOneToOne (const Teuchos::RCP<const Tpetra::Map<LO, GO, NT> >& M)
2362 {
2363  using Teuchos::Array;
2364  using Teuchos::ArrayView;
2365  using Teuchos::as;
2366  using Teuchos::rcp;
2367  typedef Tpetra::Map<LO, GO, NT> map_type;
2368  typedef global_size_t GST;
2369  const GST GINV = Tpetra::Details::OrdinalTraits<GST>::invalid ();
2370  const int myRank = M->getComm ()->getRank ();
2371 
2372  // Bypasses for special cases where either M is known to be
2373  // one-to-one, or the one-to-one version of M is easy to compute.
2374  // This is why we take M as an RCP, not as a const reference -- so
2375  // that we can return M itself if it is 1-to-1.
2376  if (! M->isDistributed ()) {
2377  // For a locally replicated Map, we assume that users want to push
2378  // all the GIDs to Process 0.
2379 
2380  // mfh 05 Nov 2013: getGlobalNumElements() does indeed return what
2381  // you think it should return, in this special case of a locally
2382  // replicated contiguous Map.
2383  const GST numGlobalEntries = M->getGlobalNumElements ();
2384  if (M->isContiguous ()) {
2385  const size_t numLocalEntries =
2386  (myRank == 0) ? as<size_t> (numGlobalEntries) : static_cast<size_t> (0);
2387  return rcp (new map_type (numGlobalEntries, numLocalEntries,
2388  M->getIndexBase (), M->getComm ()));
2389  }
2390  else {
2391  ArrayView<const GO> myGids =
2392  (myRank == 0) ? M->getNodeElementList () : Teuchos::null;
2393  return rcp (new map_type (GINV, myGids (), M->getIndexBase (),
2394  M->getComm ()));
2395  }
2396  }
2397  else if (M->isContiguous ()) {
2398  // Contiguous, distributed Maps are one-to-one by construction.
2399  // (Locally replicated Maps can be contiguous.)
2400  return M;
2401  }
2402  else {
2404  const size_t numMyElems = M->getNodeNumElements ();
2405  ArrayView<const GO> myElems = M->getNodeElementList ();
2406  Array<int> owner_procs_vec (numMyElems);
2407 
2408  directory.getDirectoryEntries (*M, myElems, owner_procs_vec ());
2409 
2410  Array<GO> myOwned_vec (numMyElems);
2411  size_t numMyOwnedElems = 0;
2412  for (size_t i = 0; i < numMyElems; ++i) {
2413  const GO GID = myElems[i];
2414  const int owner = owner_procs_vec[i];
2415 
2416  if (myRank == owner) {
2417  myOwned_vec[numMyOwnedElems++] = GID;
2418  }
2419  }
2420  myOwned_vec.resize (numMyOwnedElems);
2421 
2422  return rcp (new map_type (GINV, myOwned_vec (), M->getIndexBase (),
2423  M->getComm ()));
2424  }
2425 }
2426 
2427 template<class LocalOrdinal, class GlobalOrdinal, class Node>
2428 Teuchos::RCP<const Tpetra::Map<LocalOrdinal,GlobalOrdinal,Node> >
2431 {
2432  using ::Tpetra::Details::Behavior;
2433  using Teuchos::Array;
2434  using Teuchos::ArrayView;
2435  using Teuchos::RCP;
2436  using Teuchos::rcp;
2437  using Teuchos::toString;
2438  using std::cerr;
2439  using std::endl;
2440  using LO = LocalOrdinal;
2441  using GO = GlobalOrdinal;
2442  using map_type = Tpetra::Map<LO, GO, Node>;
2443  const char funcPrefix[] = "Tpetra::createOneToOne(Map,TieBreak): ";
2444 
2445  const bool verbose = Behavior::verbose ("Map") ||
2446  Behavior::verbose ("Directory");
2447  std::unique_ptr<std::string> procPrefix;
2448  if (verbose) {
2449  std::ostringstream os;
2450  os << "Proc ";
2451  if (M.is_null () || M->getComm ().is_null ()) {
2452  os << "?";
2453  }
2454  else {
2455  os << M->getComm ()->getRank ();
2456  }
2457  os << ": ";
2458  procPrefix = std::unique_ptr<std::string> (new std::string (os.str ()));
2459  os << funcPrefix << "Start" << endl;
2460  cerr << os.str ();
2461  }
2462 
2463  // FIXME (mfh 20 Feb 2013) We should have a bypass for contiguous
2464  // Maps (which are 1-to-1 by construction).
2465 
2466  //Based off Epetra's one to one.
2467 
2469  if (verbose) {
2470  std::ostringstream os;
2471  os << *procPrefix << "Initialize Directory" << endl;
2472  cerr << os.str ();
2473  }
2474  directory.initialize (*M, tie_break);
2475  if (verbose) {
2476  std::ostringstream os;
2477  os << *procPrefix << "Done initializing Directory" << endl;
2478  cerr << os.str ();
2479  }
2480  size_t numMyElems = M->getNodeNumElements ();
2481  ArrayView<const GO> myElems = M->getNodeElementList ();
2482  Array<int> owner_procs_vec (numMyElems);
2483  if (verbose) {
2484  std::ostringstream os;
2485  os << *procPrefix << "Call Directory::getDirectoryEntries with "
2486  "GIDs " << toString (myElems) << endl;
2487  cerr << os.str ();
2488  }
2489  directory.getDirectoryEntries (*M, myElems, owner_procs_vec ());
2490  if (verbose) {
2491  std::ostringstream os;
2492  os << *procPrefix << "Directory::getDirectoryEntries PIDs "
2493  "result: " << toString (owner_procs_vec) << endl;
2494  cerr << os.str ();
2495  }
2496 
2497  const int myRank = M->getComm()->getRank();
2498  Array<GO> myOwned_vec (numMyElems);
2499  size_t numMyOwnedElems = 0;
2500  for (size_t i = 0; i < numMyElems; ++i) {
2501  const GO GID = myElems[i];
2502  const int owner = owner_procs_vec[i];
2503  if (myRank == owner) {
2504  myOwned_vec[numMyOwnedElems++] = GID;
2505  }
2506  }
2507  myOwned_vec.resize (numMyOwnedElems);
2508 
2509  // FIXME (mfh 08 May 2014) The above Directory should be perfectly
2510  // valid for the new Map. Why can't we reuse it?
2511  const global_size_t GINV =
2512  Tpetra::Details::OrdinalTraits<global_size_t>::invalid ();
2513  if (verbose) {
2514  std::ostringstream os;
2515  os << *procPrefix << "Create Map with GIDs "
2516  << toString (myOwned_vec) << endl;
2517  cerr << os.str ();
2518  }
2519  RCP<const map_type> retMap
2520  (new map_type (GINV, myOwned_vec (), M->getIndexBase (),
2521  M->getComm ()));
2522  if (verbose) {
2523  std::ostringstream os;
2524  os << *procPrefix << funcPrefix << "Done!" << endl;
2525  cerr << os.str ();
2526  }
2527  return retMap;
2528 }
2529 
2530 //
2531 // Explicit instantiation macro
2532 //
2533 // Must be expanded from within the Tpetra namespace!
2534 //
2535 
2537 #ifdef TPETRA_ENABLE_DEPRECATED_CODE
2538 
2539 #define TPETRA_MAP_INSTANT(LO,GO,NODE) \
2540  \
2541  template class Map< LO , GO , NODE >; \
2542  \
2543  template Teuchos::RCP< const Map<LO,GO,NODE> > \
2544  createLocalMapWithNode<LO,GO,NODE> (const size_t numElements, \
2545  const Teuchos::RCP< const Teuchos::Comm< int > >& comm); \
2546  \
2547  template Teuchos::RCP< const Map<LO,GO,NODE> > \
2548  createContigMapWithNode<LO,GO,NODE> (const global_size_t numElements, \
2549  const size_t localNumElements, \
2550  const Teuchos::RCP< const Teuchos::Comm< int > >& comm); \
2551  \
2552  template Teuchos::RCP< const Map<LO,GO,NODE> > \
2553  createNonContigMapWithNode(const Teuchos::ArrayView<const GO> &elementList, \
2554  const Teuchos::RCP<const Teuchos::Comm<int> > &comm); \
2555  \
2556  template Teuchos::RCP< const Map<LO,GO,NODE> > \
2557  createUniformContigMapWithNode<LO,GO,NODE> (const global_size_t numElements, \
2558  const Teuchos::RCP< const Teuchos::Comm< int > >& comm); \
2559  \
2560  template Teuchos::RCP< const Map<LO,GO,NODE> > \
2561  createLocalMapWithNode<LO,GO,NODE> (const size_t numElements, \
2562  const Teuchos::RCP< const Teuchos::Comm< int > >& comm, \
2563  const Teuchos::RCP< NODE >& node); \
2564  \
2565  template Teuchos::RCP< const Map<LO,GO,NODE> > \
2566  createContigMapWithNode<LO,GO,NODE> (const global_size_t numElements, \
2567  const size_t localNumElements, \
2568  const Teuchos::RCP< const Teuchos::Comm< int > >& comm, \
2569  const Teuchos::RCP< NODE > &node); \
2570  \
2571  template Teuchos::RCP< const Map<LO,GO,NODE> > \
2572  createNonContigMapWithNode(const Teuchos::ArrayView<const GO> &elementList, \
2573  const Teuchos::RCP<const Teuchos::Comm<int> > &comm, \
2574  const Teuchos::RCP<NODE> &node); \
2575  \
2576  template Teuchos::RCP< const Map<LO,GO,NODE> > \
2577  createUniformContigMapWithNode<LO,GO,NODE> (const global_size_t numElements, \
2578  const Teuchos::RCP< const Teuchos::Comm< int > >& comm, \
2579  const Teuchos::RCP< NODE > &node); \
2580  \
2581  template Teuchos::RCP< const Map<LO,GO,NODE> > \
2582  createWeightedContigMapWithNode<LO,GO,NODE> (const int thisNodeWeight, \
2583  const global_size_t numElements, \
2584  const Teuchos::RCP< const Teuchos::Comm< int > >& comm, \
2585  const Teuchos::RCP< NODE >& node); \
2586  \
2587  template Teuchos::RCP<const Map<LO,GO,NODE> > \
2588  createOneToOne (const Teuchos::RCP<const Map<LO,GO,NODE> >& M); \
2589  \
2590  template Teuchos::RCP<const Map<LO,GO,NODE> > \
2591  createOneToOne (const Teuchos::RCP<const Map<LO,GO,NODE> >& M, \
2592  const Tpetra::Details::TieBreak<LO,GO>& tie_break); \
2593 
2594 #else // !TPETRA_ENABLE_DEPRECATED_CODE
2595 
2596 #define TPETRA_MAP_INSTANT(LO,GO,NODE) \
2597  \
2598  template class Map< LO , GO , NODE >; \
2599  \
2600  template Teuchos::RCP< const Map<LO,GO,NODE> > \
2601  createLocalMapWithNode<LO,GO,NODE> (const size_t numElements, \
2602  const Teuchos::RCP< const Teuchos::Comm< int > >& comm); \
2603  \
2604  template Teuchos::RCP< const Map<LO,GO,NODE> > \
2605  createContigMapWithNode<LO,GO,NODE> (const global_size_t numElements, \
2606  const size_t localNumElements, \
2607  const Teuchos::RCP< const Teuchos::Comm< int > >& comm); \
2608  \
2609  template Teuchos::RCP< const Map<LO,GO,NODE> > \
2610  createNonContigMapWithNode(const Teuchos::ArrayView<const GO> &elementList, \
2611  const Teuchos::RCP<const Teuchos::Comm<int> > &comm); \
2612  \
2613  template Teuchos::RCP< const Map<LO,GO,NODE> > \
2614  createUniformContigMapWithNode<LO,GO,NODE> (const global_size_t numElements, \
2615  const Teuchos::RCP< const Teuchos::Comm< int > >& comm); \
2616  \
2617  template Teuchos::RCP<const Map<LO,GO,NODE> > \
2618  createOneToOne (const Teuchos::RCP<const Map<LO,GO,NODE> >& M); \
2619  \
2620  template Teuchos::RCP<const Map<LO,GO,NODE> > \
2621  createOneToOne (const Teuchos::RCP<const Map<LO,GO,NODE> >& M, \
2622  const Tpetra::Details::TieBreak<LO,GO>& tie_break); \
2623 
2624 #endif // TPETRA_ENABLE_DEPRECATED_CODE
2625 
2627 #define TPETRA_MAP_INSTANT_DEFAULTNODE(LO,GO) \
2628  template Teuchos::RCP< const Map<LO,GO> > \
2629  createLocalMap<LO,GO>( const size_t, const Teuchos::RCP< const Teuchos::Comm< int > > &); \
2630  \
2631  template Teuchos::RCP< const Map<LO,GO> > \
2632  createContigMap<LO,GO>( global_size_t, size_t, \
2633  const Teuchos::RCP< const Teuchos::Comm< int > > &); \
2634  \
2635  template Teuchos::RCP< const Map<LO,GO> > \
2636  createNonContigMap(const Teuchos::ArrayView<const GO> &, \
2637  const Teuchos::RCP<const Teuchos::Comm<int> > &); \
2638  \
2639  template Teuchos::RCP< const Map<LO,GO> > \
2640  createUniformContigMap<LO,GO>( const global_size_t, \
2641  const Teuchos::RCP< const Teuchos::Comm< int > > &); \
2642 
2643 #endif // TPETRA_MAP_DEF_HPP
Tpetra::Map::getMinGlobalIndex
GlobalOrdinal getMinGlobalIndex() const
The minimum global index owned by the calling process.
Definition: Tpetra_Map_decl.hpp:663
Tpetra::Map::isOneToOne
bool isOneToOne() const
Whether the Map is one to one.
Definition: Tpetra_Map_def.hpp:1207
Tpetra::createOneToOne
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,...
Tpetra::createUniformContigMap
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.
Tpetra::IDNotPresent
@ IDNotPresent
Definition: Tpetra_ConfigDefs.hpp:126
Tpetra::Details::congruent
bool congruent(const Teuchos::Comm< int > &comm1, const Teuchos::Comm< int > &comm2)
Whether the two communicators are congruent.
Definition: Tpetra_Util.cpp:65
Tpetra::Map::replaceCommWithSubset
Teuchos::RCP< const Map< LocalOrdinal, GlobalOrdinal, Node > > replaceCommWithSubset(const Teuchos::RCP< const Teuchos::Comm< int > > &newComm) const
Replace this Map's communicator with a subset communicator.
Definition: Tpetra_Map_def.hpp:1821
Tpetra::Map::isLocallyFitted
bool isLocallyFitted(const Map< LocalOrdinal, GlobalOrdinal, Node > &map) const
True if and only if map is locally fitted to this Map.
Definition: Tpetra_Map_def.hpp:1461
Tpetra::Directory::initialize
void initialize(const map_type &map)
Initialize the Directory with its Map.
Tpetra::Map::removeEmptyProcesses
Teuchos::RCP< const Map< LocalOrdinal, GlobalOrdinal, Node > > removeEmptyProcesses() const
Advanced methods.
Definition: Tpetra_Map_def.hpp:1932
Tpetra::Details::TieBreak
Interface for breaking ties in ownership.
Definition: Tpetra_TieBreak.hpp:68
Tpetra::Map::getNodeElementList
Teuchos::ArrayView< const GlobalOrdinal > getNodeElementList() const
Return a NONOWNING view of the global indices owned by this process.
Definition: Tpetra_Map_def.hpp:1650
Tpetra::createContigMap
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...
Tpetra::Map::device_type
typename Node::device_type device_type
This class' Kokkos::Device specialization.
Definition: Tpetra_Map_decl.hpp:262
Tpetra::Map::getGlobalElement
GlobalOrdinal getGlobalElement(LocalOrdinal localIndex) const
The global index corresponding to the given local index.
Definition: Tpetra_Map_def.hpp:1246
Tpetra::Map::~Map
virtual ~Map()
Destructor (virtual for memory safety of derived classes).
Definition: Tpetra_Map_def.hpp:1155
Tpetra::Map::isNodeGlobalElement
bool isNodeGlobalElement(GlobalOrdinal globalIndex) const
Whether the given global index is owned by this Map on the calling process.
Definition: Tpetra_Map_def.hpp:1278
Tpetra_Details_Behavior.hpp
Declaration of Tpetra::Details::Behavior, a class that describes Tpetra's behavior.
Tpetra::Map::getMaxGlobalIndex
GlobalOrdinal getMaxGlobalIndex() const
The maximum global index owned by the calling process.
Definition: Tpetra_Map_decl.hpp:672
Tpetra::Map
A parallel distribution of indices over processes.
Definition: Tpetra_Map_decl.hpp:246
Tpetra_Details_initializeKokkos.hpp
Declaration of Tpetra::Details::initializeKokkos.
Tpetra::createLocalMap
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.
Tpetra::createUniformContigMapWithNode
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.
Tpetra::Map::isSameAs
bool isSameAs(const Map< LocalOrdinal, GlobalOrdinal, Node > &map) const
True if and only if map is identical to this Map.
Definition: Tpetra_Map_def.hpp:1506
Tpetra_Details_printOnce.hpp
Declaration of Tpetra::Details::printOnce.
Details
Implementation details of Tpetra.
Tpetra::Details::gathervPrint
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,...
Definition: Tpetra_Details_gathervPrint.cpp:52
Tpetra::Details::Behavior::debug
static bool debug()
Whether Tpetra is in debug mode.
Definition: Tpetra_Details_Behavior.cpp:192
Tpetra::Map::node_type
Node node_type
Legacy typedef that will go away at some point.
Definition: Tpetra_Map_decl.hpp:271
Tpetra::Map::getMinAllGlobalIndex
GlobalOrdinal getMinAllGlobalIndex() const
The minimum global index over all processes in the communicator.
Definition: Tpetra_Map_decl.hpp:681
Tpetra::createLocalMapWithNode
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.
Tpetra::createNonContigMapWithNode
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 ...
Tpetra::createNonContigMap
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.
Tpetra::AllIDsPresent
@ AllIDsPresent
Definition: Tpetra_ConfigDefs.hpp:125
Tpetra::LocalGlobal
LocalGlobal
Enum for local versus global allocation of Map entries.
Definition: Tpetra_ConfigDefs.hpp:118
Tpetra::Map::getNodeNumElements
size_t getNodeNumElements() const
The number of elements belonging to the calling process.
Definition: Tpetra_Map_decl.hpp:618
Tpetra::Directory::getDirectoryEntries
LookupStatus getDirectoryEntries(const map_type &map, const Teuchos::ArrayView< const GlobalOrdinal > &globalIDs, const Teuchos::ArrayView< int > &nodeIDs) const
Given a global ID list, return the list of their owning process IDs.
Tpetra::Map::getLocalMap
local_map_type getLocalMap() const
Get the local Map for Kokkos kernels.
Definition: Tpetra_Map_def.hpp:1297
Tpetra_Details_checkPointer.hpp
Declaration of functions for checking whether a given pointer is accessible from a given Kokkos execu...
Tpetra::Map::getComm
Teuchos::RCP< const Teuchos::Comm< int > > getComm() const
Accessors for the Teuchos::Comm and Kokkos Node objects.
Definition: Tpetra_Map_def.hpp:2102
Tpetra::Map::describe
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.
Definition: Tpetra_Map_def.hpp:1746
Tpetra::Details::memorySpaceName
std::string memorySpaceName(const void *ptr)
Return the Kokkos memory space name (without "Kokkos::") corresponding to the given nonnull pointer.
Definition: Tpetra_Details_checkPointer.cpp:148
Tpetra::Details::FixedHashTable< GO, LO, device_type >
Tpetra_Core.hpp
Functions for initializing and finalizing Tpetra.
Tpetra::Details::Behavior::verbose
static bool verbose()
Whether Tpetra is in verbose mode.
Definition: Tpetra_Details_Behavior.cpp:205
Tpetra::Map::getGlobalNumElements
global_size_t getGlobalNumElements() const
The number of elements in this Map.
Definition: Tpetra_Map_decl.hpp:609
Tpetra::Map< LO, GO, NT >::execution_space
typename device_type::execution_space execution_space
The Kokkos execution space.
Definition: Tpetra_Map_decl.hpp:265
Tpetra::LookupStatus
LookupStatus
Return status of Map remote index lookup (getRemoteIndexList()).
Definition: Tpetra_ConfigDefs.hpp:124
Tpetra::Map::getLocalElement
LocalOrdinal getLocalElement(GlobalOrdinal globalIndex) const
The local index corresponding to the given global index.
Definition: Tpetra_Map_def.hpp:1223
Tpetra::Map::getMyGlobalIndices
global_indices_array_type getMyGlobalIndices() const
Return a view of the global indices owned by this process.
Definition: Tpetra_Map_def.hpp:1599
Tpetra_Util.hpp
Stand-alone utility functions and macros.
Tpetra::Map::isUniform
bool isUniform() const
Whether the range of global indices is uniform.
Definition: Tpetra_Map_def.hpp:1284
Tpetra::Map::getRemoteIndexList
LookupStatus getRemoteIndexList(const Teuchos::ArrayView< const GlobalOrdinal > &GIDList, const Teuchos::ArrayView< int > &nodeIDList, const Teuchos::ArrayView< LocalOrdinal > &LIDList) const
Return the process ranks and corresponding local indices for the given global indices.
Definition: Tpetra_Map_def.hpp:2041
Tpetra::Map::getMaxAllGlobalIndex
GlobalOrdinal getMaxAllGlobalIndex() const
The maximum global index over all processes in the communicator.
Definition: Tpetra_Map_decl.hpp:690
Tpetra::Map::description
std::string description() const
Implementation of Teuchos::Describable.
Definition: Tpetra_Map_def.hpp:1675
Tpetra::Directory
Implement mapping from global ID to process ID and local ID.
Definition: Tpetra_Directory_decl.hpp:126
Tpetra::Map::isNodeLocalElement
bool isNodeLocalElement(LocalOrdinal localIndex) const
Whether the given local index is valid for this Map on the calling process.
Definition: Tpetra_Map_def.hpp:1266
Tpetra::Map::isCompatible
bool isCompatible(const Map< LocalOrdinal, GlobalOrdinal, Node > &map) const
True if and only if map is compatible with this Map.
Definition: Tpetra_Map_def.hpp:1308
Tpetra::createContigMapWithNode
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...
Tpetra::Map::isContiguous
bool isContiguous() const
True if this Map is distributed contiguously, else false.
Definition: Tpetra_Map_def.hpp:1289
Tpetra_Details_extractMpiCommFromTeuchos.hpp
Declaration of Tpetra::Details::extractMpiCommFromTeuchos.
Tpetra::Details::pointerAccessibleFromExecutionSpace
bool pointerAccessibleFromExecutionSpace(const void *ptr, const ExecutionSpace &space)
Is the given nonnull ptr accessible from the given execution space?
Definition: Tpetra_Details_checkPointer.hpp:99
Tpetra::global_size_t
size_t global_size_t
Global size_t object.
Definition: Tpetra_ConfigDefs.hpp:109
Tpetra::Details::LocalMap
"Local" part of Map suitable for Kokkos kernels.
Definition: Tpetra_Details_LocalMap.hpp:71
Tpetra::Map::global_ordinal_type
GlobalOrdinal global_ordinal_type
The type of global indices.
Definition: Tpetra_Map_decl.hpp:255
Tpetra
Namespace Tpetra contains the class and methods constituting the Tpetra library.
Tpetra::deep_copy
void deep_copy(MultiVector< DS, DL, DG, DN > &dst, const MultiVector< SS, SL, SG, SN > &src)
Copy the contents of the MultiVector src into dst.
Definition: Tpetra_MultiVector_decl.hpp:2557
Tpetra::Map::locallySameAs
bool locallySameAs(const Map< LocalOrdinal, GlobalOrdinal, node_type > &map) const
Is this Map locally the same as the input Map?
Definition: Tpetra_Map_def.hpp:1374
Tpetra::Map::getIndexBase
GlobalOrdinal getIndexBase() const
The index base for this Map.
Definition: Tpetra_Map_decl.hpp:627
Tpetra::Map::isDistributed
bool isDistributed() const
Whether this Map is globally distributed or locally replicated.
Definition: Tpetra_Map_def.hpp:1670
Tpetra::Details::initializeKokkos
void initializeKokkos()
Initialize Kokkos, using command-line arguments (if any) given to Teuchos::GlobalMPISession.
Definition: Tpetra_Details_initializeKokkos.cpp:53