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
51 #include "Tpetra_Details_FixedHashTable.hpp"
52 #include "Tpetra_Util.hpp"
53 #include "Teuchos_as.hpp"
54 #include <stdexcept>
55 
56 namespace Tpetra {
57  template <class LocalOrdinal, class GlobalOrdinal, class Node>
59  Map () :
60  comm_ (new Teuchos::SerialComm<int> ()),
61  node_ (KokkosClassic::Details::getNode<Node> ()),
62  indexBase_ (0),
63  numGlobalElements_ (0),
64  numLocalElements_ (0),
65  minMyGID_ (Tpetra::Details::OrdinalTraits<GlobalOrdinal>::invalid ()),
66  maxMyGID_ (Tpetra::Details::OrdinalTraits<GlobalOrdinal>::invalid ()),
67  minAllGID_ (Tpetra::Details::OrdinalTraits<GlobalOrdinal>::invalid ()),
68  maxAllGID_ (Tpetra::Details::OrdinalTraits<GlobalOrdinal>::invalid ()),
69  firstContiguousGID_ (Tpetra::Details::OrdinalTraits<GlobalOrdinal>::invalid ()),
70  lastContiguousGID_ (Tpetra::Details::OrdinalTraits<GlobalOrdinal>::invalid ()),
71  uniform_ (false), // trivially
72  contiguous_ (false),
73  distributed_ (false), // no communicator yet
74  directory_ (new Directory<LocalOrdinal, GlobalOrdinal, Node> ())
75  {}
76 
77  template <class LocalOrdinal, class GlobalOrdinal, class Node>
79  Map (global_size_t numGlobalElements,
80  GlobalOrdinal indexBase,
81  const Teuchos::RCP<const Teuchos::Comm<int> > &comm,
82  LocalGlobal lOrG,
83  const Teuchos::RCP<Node> &node) :
84  comm_ (comm),
85  node_ (node),
86  uniform_ (true),
87  directory_ (new Directory<LocalOrdinal, GlobalOrdinal, Node> ())
88  {
89  using Teuchos::as;
90  using Teuchos::broadcast;
91  using Teuchos::outArg;
92  using Teuchos::reduceAll;
93  using Teuchos::REDUCE_MIN;
94  using Teuchos::REDUCE_MAX;
95  using Teuchos::typeName;
96  typedef GlobalOrdinal GO;
97  typedef global_size_t GST;
99 
100 #ifdef HAVE_TPETRA_DEBUG
101  // In debug mode only, check whether numGlobalElements and
102  // indexBase are the same over all processes in the communicator.
103  {
104  GST proc0NumGlobalElements = numGlobalElements;
105  broadcast<int, GST> (*comm_, 0, outArg (proc0NumGlobalElements));
106  GST minNumGlobalElements = numGlobalElements;
107  GST maxNumGlobalElements = numGlobalElements;
108  reduceAll<int, GST> (*comm, REDUCE_MIN, numGlobalElements, outArg (minNumGlobalElements));
109  reduceAll<int, GST> (*comm, REDUCE_MAX, numGlobalElements, outArg (maxNumGlobalElements));
110  TEUCHOS_TEST_FOR_EXCEPTION(
111  minNumGlobalElements != maxNumGlobalElements || numGlobalElements != minNumGlobalElements,
112  std::invalid_argument,
113  "Tpetra::Map constructor: All processes must provide the same number "
114  "of global elements. Process 0 set numGlobalElements = "
115  << proc0NumGlobalElements << ". The calling process "
116  << comm->getRank () << " set numGlobalElements = " << numGlobalElements
117  << ". The min and max values over all processes are "
118  << minNumGlobalElements << " resp. " << maxNumGlobalElements << ".");
119 
120  GO proc0IndexBase = indexBase;
121  broadcast<int, GO> (*comm_, 0, outArg (proc0IndexBase));
122  GO minIndexBase = indexBase;
123  GO maxIndexBase = indexBase;
124  reduceAll<int, GO> (*comm, REDUCE_MIN, indexBase, outArg (minIndexBase));
125  reduceAll<int, GO> (*comm, REDUCE_MAX, indexBase, outArg (maxIndexBase));
126  TEUCHOS_TEST_FOR_EXCEPTION(
127  minIndexBase != maxIndexBase || indexBase != minIndexBase,
128  std::invalid_argument,
129  "Tpetra::Map constructor: "
130  "All processes must provide the same indexBase argument. "
131  "Process 0 set indexBase = " << proc0IndexBase << ". The calling "
132  "process " << comm->getRank () << " set indexBase = " << indexBase
133  << ". The min and max values over all processes are "
134  << minIndexBase << " resp. " << maxIndexBase << ".");
135  }
136 #endif // HAVE_TPETRA_DEBUG
137 
138  // Distribute the elements across the processes in the given
139  // communicator so that global IDs (GIDs) are
140  //
141  // - Nonoverlapping (only one process owns each GID)
142  // - Contiguous (the sequence of GIDs is nondecreasing, and no two
143  // adjacent GIDs differ by more than one)
144  // - As evenly distributed as possible (the numbers of GIDs on two
145  // different processes do not differ by more than one)
146 
147  // All processes have the same numGlobalElements, but we still
148  // need to check that it is valid. numGlobalElements must be
149  // positive and not the "invalid" value (GSTI).
150  //
151  // This comparison looks funny, but it avoids compiler warnings
152  // for comparing unsigned integers (numGlobalElements_in is a
153  // GST, which is unsigned) while still working if we
154  // later decide to make GST signed.
155  TEUCHOS_TEST_FOR_EXCEPTION(
156  (numGlobalElements < 1 && numGlobalElements != 0),
157  std::invalid_argument,
158  "Tpetra::Map constructor: numGlobalElements (= "
159  << numGlobalElements << ") must be nonnegative.");
160 
161  TEUCHOS_TEST_FOR_EXCEPTION(
162  numGlobalElements == GSTI, std::invalid_argument,
163  "Tpetra::Map constructor: You provided numGlobalElements = Teuchos::"
164  "OrdinalTraits<Tpetra::global_size_t>::invalid(). This version of the "
165  "constructor requires a valid value of numGlobalElements. You "
166  "probably mistook this constructor for the \"contiguous nonuniform\" "
167  "constructor, which can compute the global number of elements for you "
168  "if you set numGlobalElements to that value.");
169 
170  size_t numLocalElements = 0; // will set below
171  if (lOrG == GloballyDistributed) {
172  // Compute numLocalElements:
173  //
174  // If numGlobalElements == numProcs * B + remainder,
175  // then Proc r gets B+1 elements if r < remainder,
176  // and B elements if r >= remainder.
177  //
178  // This strategy is valid for any value of numGlobalElements and
179  // numProcs, including the following border cases:
180  // - numProcs == 1
181  // - numLocalElements < numProcs
182  //
183  // In the former case, remainder == 0 && numGlobalElements ==
184  // numLocalElements. In the latter case, remainder ==
185  // numGlobalElements && numLocalElements is either 0 or 1.
186  const GST numProcs = static_cast<GST> (comm_->getSize ());
187  const GST myRank = static_cast<GST> (comm_->getRank ());
188  const GST quotient = numGlobalElements / numProcs;
189  const GST remainder = numGlobalElements - quotient * numProcs;
190 
191  GO startIndex;
192  if (myRank < remainder) {
193  numLocalElements = static_cast<size_t> (1) + static_cast<size_t> (quotient);
194  // myRank was originally an int, so it should never overflow
195  // reasonable GO types.
196  startIndex = as<GO> (myRank) * as<GO> (numLocalElements);
197  } else {
198  numLocalElements = as<size_t> (quotient);
199  startIndex = as<GO> (myRank) * as<GO> (numLocalElements) +
200  as<GO> (remainder);
201  }
202 
203  minMyGID_ = indexBase + startIndex;
204  maxMyGID_ = indexBase + startIndex + numLocalElements - 1;
205  minAllGID_ = indexBase;
206  maxAllGID_ = indexBase + numGlobalElements - 1;
207  distributed_ = (numProcs > 1);
208  }
209  else { // lOrG == LocallyReplicated
210  numLocalElements = as<size_t> (numGlobalElements);
211  minMyGID_ = indexBase;
212  maxMyGID_ = indexBase + numGlobalElements - 1;
213  distributed_ = false;
214  }
215 
216  minAllGID_ = indexBase;
217  maxAllGID_ = indexBase + numGlobalElements - 1;
218  indexBase_ = indexBase;
219  numGlobalElements_ = numGlobalElements;
220  numLocalElements_ = numLocalElements;
221  firstContiguousGID_ = minMyGID_;
222  lastContiguousGID_ = maxMyGID_;
223  contiguous_ = true;
224 
225  // Create the Directory on demand in getRemoteIndexList().
226  //setupDirectory ();
227  }
228 
229  template <class LocalOrdinal, class GlobalOrdinal, class Node>
231  Map (global_size_t numGlobalElements,
232  size_t numLocalElements,
233  GlobalOrdinal indexBase,
234  const Teuchos::RCP<const Teuchos::Comm<int> > &comm,
235  const Teuchos::RCP<Node> &node) :
236  comm_ (comm),
237  node_ (node),
238  uniform_ (false),
239  directory_ (new Directory<LocalOrdinal, GlobalOrdinal, Node> ())
240  {
241  using Teuchos::as;
242  using Teuchos::broadcast;
243  using Teuchos::outArg;
244  using Teuchos::reduceAll;
245  using Teuchos::REDUCE_MIN;
246  using Teuchos::REDUCE_MAX;
247  using Teuchos::REDUCE_SUM;
248  using Teuchos::scan;
249  typedef GlobalOrdinal GO;
250  typedef global_size_t GST;
252 
253 #ifdef HAVE_TPETRA_DEBUG
254  // Keep this for later debug checks.
255  GST debugGlobalSum = 0; // Will be global sum of numLocalElements
256  reduceAll<int, GST> (*comm, REDUCE_SUM, as<GST> (numLocalElements),
257  outArg (debugGlobalSum));
258  // In debug mode only, check whether numGlobalElements and
259  // indexBase are the same over all processes in the communicator.
260  {
261  GST proc0NumGlobalElements = numGlobalElements;
262  broadcast<int, GST> (*comm_, 0, outArg (proc0NumGlobalElements));
263  GST minNumGlobalElements = numGlobalElements;
264  GST maxNumGlobalElements = numGlobalElements;
265  reduceAll<int, GST> (*comm, REDUCE_MIN, numGlobalElements, outArg (minNumGlobalElements));
266  reduceAll<int, GST> (*comm, REDUCE_MAX, numGlobalElements, outArg (maxNumGlobalElements));
267  TEUCHOS_TEST_FOR_EXCEPTION(
268  minNumGlobalElements != maxNumGlobalElements || numGlobalElements != minNumGlobalElements,
269  std::invalid_argument,
270  "Tpetra::Map constructor: All processes must provide the same number "
271  "of global elements. This is true even if that argument is Teuchos::"
272  "OrdinalTraits<global_size_t>::invalid() to signal that the Map should "
273  "compute the global number of elements. Process 0 set numGlobalElements"
274  " = " << proc0NumGlobalElements << ". The calling process "
275  << comm->getRank () << " set numGlobalElements = " << numGlobalElements
276  << ". The min and max values over all processes are "
277  << minNumGlobalElements << " resp. " << maxNumGlobalElements << ".");
278 
279  GO proc0IndexBase = indexBase;
280  broadcast<int, GO> (*comm_, 0, outArg (proc0IndexBase));
281  GO minIndexBase = indexBase;
282  GO maxIndexBase = indexBase;
283  reduceAll<int, GO> (*comm, REDUCE_MIN, indexBase, outArg (minIndexBase));
284  reduceAll<int, GO> (*comm, REDUCE_MAX, indexBase, outArg (maxIndexBase));
285  TEUCHOS_TEST_FOR_EXCEPTION(
286  minIndexBase != maxIndexBase || indexBase != minIndexBase,
287  std::invalid_argument,
288  "Tpetra::Map constructor: "
289  "All processes must provide the same indexBase argument. "
290  "Process 0 set indexBase = " << proc0IndexBase << ". The calling "
291  "process " << comm->getRank () << " set indexBase = " << indexBase
292  << ". The min and max values over all processes are "
293  << minIndexBase << " resp. " << maxIndexBase << ".");
294 
295  // Make sure that the sum of numLocalElements over all processes
296  // equals numGlobalElements.
297  TEUCHOS_TEST_FOR_EXCEPTION(
298  numGlobalElements != GSTI && debugGlobalSum != numGlobalElements,
299  std::invalid_argument,
300  "Tpetra::Map constructor: The sum of numLocalElements over all "
301  "processes = " << debugGlobalSum << " != numGlobalElements = "
302  << numGlobalElements << ". If you would like this constructor to "
303  "compute numGlobalElements for you, you may set numGlobalElements = "
304  "Teuchos::OrdinalTraits<Tpetra::global_size_t>::invalid() on input.");
305  }
306 #endif // HAVE_TPETRA_DEBUG
307 
308  // Distribute the elements across the nodes so that they are
309  // - non-overlapping
310  // - contiguous
311 
312  // This differs from the first Map constructor (that only takes a
313  // global number of elements) in that the user has specified the
314  // number of local elements, so that the elements are not
315  // (necessarily) evenly distributed over the processes.
316 
317  // Compute my local offset. This is an inclusive scan, so to get
318  // the final offset, we subtract off the input.
319  GO scanResult = 0;
320  scan<int, GO> (*comm, REDUCE_SUM, numLocalElements, outArg (scanResult));
321  const GO myOffset = scanResult - numLocalElements;
322 
323  if (numGlobalElements != GSTI) {
324  numGlobalElements_ = numGlobalElements; // Use the user's value.
325  } else {
326  // Inclusive scan means that the last process has the final sum.
327  // Rather than doing a reduceAll to get the sum of
328  // numLocalElements, we can just have the last process broadcast
329  // its result. That saves us a round of log(numProcs) messages.
330  const int numProcs = comm->getSize ();
331  GST globalSum = scanResult;
332  if (numProcs > 1) {
333  broadcast (*comm, numProcs - 1, outArg (globalSum));
334  }
335  numGlobalElements_ = globalSum;
336 
337 #ifdef HAVE_TPETRA_DEBUG
338  // No need for an all-reduce here; both come from collectives.
339  TEUCHOS_TEST_FOR_EXCEPTION(
340  globalSum != debugGlobalSum, std::logic_error,
341  "Tpetra::Map constructor (contiguous nonuniform): "
342  "globalSum = " << globalSum << " != debugGlobalSum = " << debugGlobalSum
343  << ". Please report this bug to the Tpetra developers.");
344 #endif // HAVE_TPETRA_DEBUG
345  }
346  numLocalElements_ = numLocalElements;
347  indexBase_ = indexBase;
348  minAllGID_ = indexBase;
349  // numGlobalElements might be GSTI; use numGlobalElements_;
350  maxAllGID_ = indexBase + numGlobalElements_ - 1;
351  minMyGID_ = indexBase + myOffset;
352  maxMyGID_ = indexBase + myOffset + numLocalElements - 1;
353  firstContiguousGID_ = minMyGID_;
354  lastContiguousGID_ = maxMyGID_;
355  contiguous_ = true;
356  distributed_ = checkIsDist ();
357 
358  // Create the Directory on demand in getRemoteIndexList().
359  //setupDirectory ();
360  }
361 
362  template <class LocalOrdinal, class GlobalOrdinal, class Node>
364  Map (global_size_t numGlobalElements,
365  const Teuchos::ArrayView<const GlobalOrdinal> &entryList,
366  GlobalOrdinal indexBase,
367  const Teuchos::RCP<const Teuchos::Comm<int> > &comm,
368  const Teuchos::RCP<Node> &node) :
369  comm_ (comm),
370  node_ (node),
371  uniform_ (false),
372  directory_ (new Directory<LocalOrdinal, GlobalOrdinal, Node> ())
373  {
374  using Teuchos::arcp;
375  using Teuchos::ArrayView;
376  using Teuchos::as;
377  using Teuchos::broadcast;
378  using Teuchos::outArg;
379  using Teuchos::ptr;
380  using Teuchos::REDUCE_MAX;
381  using Teuchos::REDUCE_MIN;
382  using Teuchos::REDUCE_SUM;
383  using Teuchos::reduceAll;
384  using Teuchos::typeName;
385  typedef LocalOrdinal LO;
386  typedef GlobalOrdinal GO;
387  typedef global_size_t GST;
388  typedef typename ArrayView<const GO>::size_type size_type;
390 
391  // The user has specified the distribution of elements over the
392  // processes, via entryList. The distribution is not necessarily
393  // contiguous or equally shared over the processes.
394 
395  // The length of entryList on this node is the number of local
396  // elements (on this node), even though entryList contains global
397  // indices. We assume that the number of local elements can be
398  // stored in a size_t; numLocalElements_ is a size_t, so this
399  // variable and that should have the same type.
400  const size_t numLocalElements = as<size_t> (entryList.size ());
401 
402 #ifdef HAVE_TPETRA_DEBUG
403  // Keep this for later debug checks.
404  GST debugGlobalSum = 0; // Will be global sum of numLocalElements
405  reduceAll<int, GST> (*comm, REDUCE_SUM, as<GST> (numLocalElements),
406  outArg (debugGlobalSum));
407  // In debug mode only, check whether numGlobalElements and
408  // indexBase are the same over all processes in the communicator.
409  {
410  GST proc0NumGlobalElements = numGlobalElements;
411  broadcast<int, GST> (*comm_, 0, outArg (proc0NumGlobalElements));
412  GST minNumGlobalElements = numGlobalElements;
413  GST maxNumGlobalElements = numGlobalElements;
414  reduceAll<int, GST> (*comm, REDUCE_MIN, numGlobalElements, outArg (minNumGlobalElements));
415  reduceAll<int, GST> (*comm, REDUCE_MAX, numGlobalElements, outArg (maxNumGlobalElements));
416  TEUCHOS_TEST_FOR_EXCEPTION(
417  minNumGlobalElements != maxNumGlobalElements || numGlobalElements != minNumGlobalElements,
418  std::invalid_argument,
419  "Tpetra::Map constructor: All processes must provide the same number "
420  "of global elements. This is true even if that argument is Teuchos::"
421  "OrdinalTraits<global_size_t>::invalid() to signal that the Map should "
422  "compute the global number of elements. Process 0 set numGlobalElements"
423  " = " << proc0NumGlobalElements << ". The calling process "
424  << comm->getRank () << " set numGlobalElements = " << numGlobalElements
425  << ". The min and max values over all processes are "
426  << minNumGlobalElements << " resp. " << maxNumGlobalElements << ".");
427 
428  GO proc0IndexBase = indexBase;
429  broadcast<int, GO> (*comm_, 0, outArg (proc0IndexBase));
430  GO minIndexBase = indexBase;
431  GO maxIndexBase = indexBase;
432  reduceAll<int, GO> (*comm, REDUCE_MIN, indexBase, outArg (minIndexBase));
433  reduceAll<int, GO> (*comm, REDUCE_MAX, indexBase, outArg (maxIndexBase));
434  TEUCHOS_TEST_FOR_EXCEPTION(
435  minIndexBase != maxIndexBase || indexBase != minIndexBase,
436  std::invalid_argument,
437  "Tpetra::Map constructor: "
438  "All processes must provide the same indexBase argument. "
439  "Process 0 set indexBase = " << proc0IndexBase << ". The calling "
440  "process " << comm->getRank () << " set indexBase = " << indexBase
441  << ". The min and max values over all processes are "
442  << minIndexBase << " resp. " << maxIndexBase << ".");
443 
444  // Make sure that the sum of numLocalElements over all processes
445  // equals numGlobalElements.
446  TEUCHOS_TEST_FOR_EXCEPTION(
447  ((numGlobalElements != GSTI) && (debugGlobalSum != numGlobalElements)),
448  std::invalid_argument,
449  "Tpetra::Map constructor: The sum of entryList.size() over all "
450  "processes = " << debugGlobalSum << " != numGlobalElements = "
451  << numGlobalElements << ". If you would like this constructor to "
452  "compute numGlobalElements for you, you may set numGlobalElements = "
453  "Teuchos::OrdinalTraits<Tpetra::global_size_t>::invalid() on input.");
454  }
455 #endif // HAVE_TPETRA_DEBUG
456 
457  // FIXME (mfh 20 Feb 2013) The global reduction is redundant,
458  // since the directory Map will have to do the same thing. We
459  // should actually do the scan and broadcast for the directory Map
460  // here, and give the computed offsets to the directory Map's
461  // constructor.
462  if (numGlobalElements != GSTI) {
463  numGlobalElements_ = numGlobalElements; // Use the user's value.
464  } else { // The user wants us to compute the sum.
465  reduceAll<int, GST> (*comm, REDUCE_SUM, as<GST> (numLocalElements),
466  outArg (numGlobalElements_));
467  }
468 
469  // mfh 20 Feb 2013: We've never quite done the right thing for
470  // duplicate GIDs here. Duplicate GIDs have always been counted
471  // distinctly in numLocalElements_, and thus should get a
472  // different LID. However, we've always used std::map or a hash
473  // table for the GID -> LID lookup table, so distinct GIDs always
474  // map to the same LID. Furthermore, the order of the input GID
475  // list matters, so it's not desirable to sort for determining
476  // uniqueness.
477  //
478  // I've chosen for now to write this code as if the input GID list
479  // contains no duplicates. If this is not desired, we could use
480  // the lookup table itself to determine uniqueness: If we haven't
481  // seen the GID before, it gets a new LID and it's added to the
482  // LID -> GID and GID -> LID tables. If we have seen the GID
483  // before, it doesn't get added to either table. I would
484  // implement this, but it would cost more to do the double lookups
485  // in the table (one to check, and one to insert).
486 
487  numLocalElements_ = numLocalElements;
488  indexBase_ = indexBase;
489 
490  minMyGID_ = indexBase_;
491  maxMyGID_ = indexBase_;
492 
493  // NOTE (mfh 27 May 2015): While finding the initial contiguous
494  // GID range requires looking at all the GIDs in the range,
495  // dismissing an interval of GIDs only requires looking at the
496  // first and last GIDs. Thus, we could do binary search backwards
497  // from the end in order to catch the common case of a contiguous
498  // interval followed by noncontiguous entries. On the other hand,
499  // we could just expose this case explicitly as yet another Map
500  // constructor, and avoid the trouble of detecting it.
501  if (numLocalElements_ > 0) {
502  // Find contiguous GID range, with the restriction that the
503  // beginning of the range starts with the first entry. While
504  // doing so, fill in the LID -> GID table.
505  Kokkos::View<GO*, device_type> lgMap ("lgMap", numLocalElements_);
506  auto lgMap_host = Kokkos::create_mirror_view (lgMap);
507 
508  firstContiguousGID_ = entryList[0];
509  lastContiguousGID_ = firstContiguousGID_+1;
510 
511  // FIXME (mfh 23 Sep 2015) We need to copy the input GIDs
512  // anyway, so we have to look at them all. The logical way to
513  // find the first noncontiguous entry would thus be to "reduce,"
514  // where the local reduction result is whether entryList[i] + 1
515  // == entryList[i+1].
516 
517  lgMap_host[0] = firstContiguousGID_;
518  size_t i = 1;
519  for ( ; i < numLocalElements_; ++i) {
520  const GO curGid = entryList[i];
521  const LO curLid = as<LO> (i);
522 
523  if (lastContiguousGID_ != curGid) break;
524 
525  // Add the entry to the LID->GID table only after we know that
526  // the current GID is in the initial contiguous sequence, so
527  // that we don't repeat adding it in the first iteration of
528  // the loop below over the remaining noncontiguous GIDs.
529  lgMap_host[curLid] = curGid;
530  ++lastContiguousGID_;
531  }
532  --lastContiguousGID_;
533 
534  // [firstContiguousGID_, lastContigousGID_] is the initial
535  // sequence of contiguous GIDs. We can start the min and max
536  // GID using this range.
537  minMyGID_ = firstContiguousGID_;
538  maxMyGID_ = lastContiguousGID_;
539 
540  // Compute the GID -> LID lookup table, _not_ including the
541  // initial sequence of contiguous GIDs.
542  ArrayView<const GO> nonContigEntries =
543  entryList (as<size_type> (i), entryList.size () - as<size_type> (i));
544  glMap_ = global_to_local_table_type (nonContigEntries, firstContiguousGID_,
545  lastContiguousGID_, as<LO> (i));
546 
547  for ( ; i < numLocalElements_; ++i) {
548  const GO curGid = entryList[i];
549  const LO curLid = as<LO> (i);
550  lgMap_host[curLid] = curGid; // LID -> GID table
551 
552  // While iterating through entryList, we compute its
553  // (process-local) min and max elements.
554  if (curGid < minMyGID_) {
555  minMyGID_ = curGid;
556  }
557  if (curGid > maxMyGID_) {
558  maxMyGID_ = curGid;
559  }
560  }
561 
562  // We filled lgMap on host above; now sync back to device.
563  Kokkos::deep_copy (lgMap, lgMap_host);
564 
565  // "Commit" the local-to-global lookup table we filled in above.
566  lgMap_ = lgMap;
567  }
568  else {
569  // This insures tests for GIDs in the range
570  // [firstContiguousGID_, lastContiguousGID_] fail for processes
571  // with no local elements.
572  firstContiguousGID_ = indexBase_+1;
573  lastContiguousGID_ = indexBase_;
574  // glMap_ was default constructed, so it's already empty.
575  }
576 
577  // Compute the min and max of all processes' GIDs. If
578  // numLocalElements_ == 0 on this process, minMyGID_ and maxMyGID_
579  // are both indexBase_. This is wrong, but fixing it would
580  // require either a fancy sparse all-reduce, or a custom reduction
581  // operator that ignores invalid values ("invalid" means
582  // Tpetra::Details::OrdinalTraits<GO>::invalid()).
583  //
584  // Also, while we're at it, use the same all-reduce to figure out
585  // if the Map is distributed. "Distributed" means that there is
586  // at least one process with a number of local elements less than
587  // the number of global elements.
588  //
589  // We're computing the min and max of all processes' GIDs using a
590  // single MAX all-reduce, because min(x,y) = -max(-x,-y) (when x
591  // and y are signed). (This lets us combine the min and max into
592  // a single all-reduce.) If each process sets localDist=1 if its
593  // number of local elements is strictly less than the number of
594  // global elements, and localDist=0 otherwise, then a MAX
595  // all-reduce on localDist tells us if the Map is distributed (1
596  // if yes, 0 if no). Thus, we can append localDist onto the end
597  // of the data and get the global result from the all-reduce.
598  if (std::numeric_limits<GO>::is_signed) {
599  // Does my process NOT own all the elements?
600  const GO localDist =
601  (as<GST> (numLocalElements_) < numGlobalElements_) ? 1 : 0;
602 
603  GO minMaxInput[3];
604  minMaxInput[0] = -minMyGID_;
605  minMaxInput[1] = maxMyGID_;
606  minMaxInput[2] = localDist;
607 
608  GO minMaxOutput[3];
609  minMaxOutput[0] = 0;
610  minMaxOutput[1] = 0;
611  minMaxOutput[2] = 0;
612  reduceAll<int, GO> (*comm, REDUCE_MAX, 3, minMaxInput, minMaxOutput);
613  minAllGID_ = -minMaxOutput[0];
614  maxAllGID_ = minMaxOutput[1];
615  const GO globalDist = minMaxOutput[2];
616  distributed_ = (comm_->getSize () > 1 && globalDist == 1);
617  }
618  else { // unsigned; use two reductions
619  // This is always correct, no matter the signedness of GO.
620  reduceAll<int, GO> (*comm_, REDUCE_MIN, minMyGID_, outArg (minAllGID_));
621  reduceAll<int, GO> (*comm_, REDUCE_MAX, maxMyGID_, outArg (maxAllGID_));
622  distributed_ = checkIsDist ();
623  }
624 
625  contiguous_ = false; // "Contiguous" is conservative.
626 
627  TEUCHOS_TEST_FOR_EXCEPTION(
628  minAllGID_ < indexBase_,
629  std::invalid_argument,
630  "Tpetra::Map constructor (noncontiguous): "
631  "Minimum global ID = " << minAllGID_ << " over all process(es) is "
632  "less than the given indexBase = " << indexBase_ << ".");
633 
634  // Create the Directory on demand in getRemoteIndexList().
635  //setupDirectory ();
636  }
637 
638 
639  template <class LocalOrdinal, class GlobalOrdinal, class Node>
641  {}
642 
643 
644  template <class LocalOrdinal, class GlobalOrdinal, class Node>
645  bool
647  {
648  TEUCHOS_TEST_FOR_EXCEPTION(
649  getComm ().is_null (), std::logic_error, "Tpetra::Map::isOneToOne: "
650  "getComm() returns null. Please report this bug to the Tpetra "
651  "developers.");
652 
653  // This is a collective operation, if it hasn't been called before.
654  setupDirectory ();
655  return directory_->isOneToOne (*this);
656  }
657 
658 
659  template <class LocalOrdinal, class GlobalOrdinal, class Node>
660  LocalOrdinal
662  getLocalElement (GlobalOrdinal globalIndex) const
663  {
664  if (isContiguous ()) {
665  if (globalIndex < getMinGlobalIndex () ||
666  globalIndex > getMaxGlobalIndex ()) {
668  }
669  return static_cast<LocalOrdinal> (globalIndex - getMinGlobalIndex ());
670  }
671  else if (globalIndex >= firstContiguousGID_ &&
672  globalIndex <= lastContiguousGID_) {
673  return static_cast<LocalOrdinal> (globalIndex - firstContiguousGID_);
674  }
675  else {
676  // If the given global index is not in the table, this returns
677  // the same value as OrdinalTraits<LocalOrdinal>::invalid().
678  return glMap_.get (globalIndex);
679  }
680  }
681 
682  template <class LocalOrdinal, class GlobalOrdinal, class Node>
683  GlobalOrdinal
685  getGlobalElement (LocalOrdinal localIndex) const
686  {
687  if (localIndex < getMinLocalIndex () || localIndex > getMaxLocalIndex ()) {
689  }
690  if (isContiguous ()) {
691  return getMinGlobalIndex () + localIndex;
692  }
693  else {
694  // This is a host Kokkos::View access, with no RCP or ArrayRCP
695  // involvement. As a result, it is thread safe.
696  //
697  // NOTE (mfh 12 Jan 2016) This assumes UVM, if lgMap_ is a CUDA
698  // device View.
699  return lgMap_[localIndex];
700  }
701  }
702 
703  template <class LocalOrdinal, class GlobalOrdinal, class Node>
704  bool
706  isNodeLocalElement (LocalOrdinal localIndex) const
707  {
708  if (localIndex < getMinLocalIndex () || localIndex > getMaxLocalIndex ()) {
709  return false;
710  } else {
711  return true;
712  }
713  }
714 
715  template <class LocalOrdinal, class GlobalOrdinal, class Node>
716  bool
718  isNodeGlobalElement (GlobalOrdinal globalIndex) const {
719  return this->getLocalElement (globalIndex) !=
721  }
722 
723  template <class LocalOrdinal, class GlobalOrdinal, class Node>
725  return uniform_;
726  }
727 
728  template <class LocalOrdinal, class GlobalOrdinal, class Node>
730  return contiguous_;
731  }
732 
733 
734  template <class LocalOrdinal, class GlobalOrdinal, class Node>
737  getLocalMap () const
738  {
739  return local_map_type (glMap_, lgMap_, getIndexBase (),
741  firstContiguousGID_, lastContiguousGID_,
743  }
744 
745  template <class LocalOrdinal, class GlobalOrdinal, class Node>
746  bool
749  {
750  using Teuchos::outArg;
751  using Teuchos::REDUCE_MIN;
752  using Teuchos::reduceAll;
753  //
754  // Tests that avoid the Boolean all-reduce below by using
755  // globally consistent quantities.
756  //
757  if (this == &map) {
758  // Pointer equality on one process always implies pointer
759  // equality on all processes, since Map is immutable.
760  return true;
761  }
762  else if (getComm ()->getSize () != map.getComm ()->getSize ()) {
763  // The two communicators have different numbers of processes.
764  // It's not correct to call isCompatible() in that case. This
765  // may result in the all-reduce hanging below.
766  return false;
767  }
768  else if (getGlobalNumElements () != map.getGlobalNumElements ()) {
769  // Two Maps are definitely NOT compatible if they have different
770  // global numbers of indices.
771  return false;
772  }
773  else if (isContiguous () && isUniform () &&
774  map.isContiguous () && map.isUniform ()) {
775  // Contiguous uniform Maps with the same number of processes in
776  // their communicators, and with the same global numbers of
777  // indices, are always compatible.
778  return true;
779  }
780  else if (! isContiguous () && ! map.isContiguous () &&
781  lgMap_.dimension_0 () != 0 && map.lgMap_.dimension_0 () != 0 &&
782  lgMap_.ptr_on_device () == map.lgMap_.ptr_on_device ()) {
783  // Noncontiguous Maps whose global index lists are nonempty and
784  // have the same pointer must be the same (and therefore
785  // contiguous).
786  //
787  // Nonempty is important. For example, consider a communicator
788  // with two processes, and two Maps that share this
789  // communicator, with zero global indices on the first process,
790  // and different nonzero numbers of global indices on the second
791  // process. In that case, on the first process, the pointers
792  // would both be NULL.
793  return true;
794  }
795 
796  TEUCHOS_TEST_FOR_EXCEPTION(
797  getGlobalNumElements () != map.getGlobalNumElements (), std::logic_error,
798  "Tpetra::Map::isCompatible: There's a bug in this method. We've already "
799  "checked that this condition is true above, but it's false here. "
800  "Please report this bug to the Tpetra developers.");
801 
802  // Do both Maps have the same number of indices on each process?
803  const int locallyCompat =
804  (getNodeNumElements () == map.getNodeNumElements ()) ? 1 : 0;
805 
806  int globallyCompat = 0;
807  reduceAll<int, int> (*comm_, REDUCE_MIN, locallyCompat, outArg (globallyCompat));
808  return (globallyCompat == 1);
809  }
810 
811  template <class LocalOrdinal, class GlobalOrdinal, class Node>
812  bool
815  {
816  using Teuchos::ArrayView;
817  typedef GlobalOrdinal GO;
818  typedef typename ArrayView<const GO>::size_type size_type;
819 
820  // If both Maps are contiguous, we can compare their GID ranges
821  // easily by looking at the min and max GID on this process.
822  // Otherwise, we'll compare their GID lists. If only one Map is
823  // contiguous, then we only have to call getNodeElementList() on
824  // the noncontiguous Map. (It's best to avoid calling it on a
825  // contiguous Map, since it results in unnecessary storage that
826  // persists for the lifetime of the Map.)
827 
828  if (getNodeNumElements () != map.getNodeNumElements ()) {
829  return false;
830  }
831  else if (getMinGlobalIndex () != map.getMinGlobalIndex () ||
832  getMaxGlobalIndex () != map.getMaxGlobalIndex ()) {
833  return false;
834  }
835  else {
836  if (isContiguous ()) {
837  if (map.isContiguous ()) {
838  return true; // min and max match, so the ranges match.
839  }
840  else { // *this is contiguous, but map is not contiguous
841  TEUCHOS_TEST_FOR_EXCEPTION(
842  ! this->isContiguous () || map.isContiguous (), std::logic_error,
843  "Tpetra::Map::locallySameAs: BUG");
844  ArrayView<const GO> rhsElts = map.getNodeElementList ();
845  const GO minLhsGid = this->getMinGlobalIndex ();
846  const size_type numRhsElts = rhsElts.size ();
847  for (size_type k = 0; k < numRhsElts; ++k) {
848  const GO curLhsGid = minLhsGid + static_cast<GO> (k);
849  if (curLhsGid != rhsElts[k]) {
850  return false; // stop on first mismatch
851  }
852  }
853  return true;
854  }
855  }
856  else if (map.isContiguous ()) { // *this is not contiguous, but map is
857  TEUCHOS_TEST_FOR_EXCEPTION(
858  this->isContiguous () || ! map.isContiguous (), std::logic_error,
859  "Tpetra::Map::locallySameAs: BUG");
860  ArrayView<const GO> lhsElts = this->getNodeElementList ();
861  const GO minRhsGid = map.getMinGlobalIndex ();
862  const size_type numLhsElts = lhsElts.size ();
863  for (size_type k = 0; k < numLhsElts; ++k) {
864  const GO curRhsGid = minRhsGid + static_cast<GO> (k);
865  if (curRhsGid != lhsElts[k]) {
866  return false; // stop on first mismatch
867  }
868  }
869  return true;
870  }
871  else if (this->lgMap_.ptr_on_device () == map.lgMap_.ptr_on_device ()) {
872  // Pointers to LID->GID "map" (actually just an array) are the
873  // same, and the number of GIDs are the same.
874  return this->getNodeNumElements () == map.getNodeNumElements ();
875  }
876  else { // we actually have to compare the GIDs
877  if (this->getNodeNumElements () != map.getNodeNumElements ()) {
878  return false; // We already checked above, but check just in case
879  }
880  else {
881  ArrayView<const GO> lhsElts = getNodeElementList ();
882  ArrayView<const GO> rhsElts = map.getNodeElementList ();
883 
884  // std::equal requires that the latter range is as large as
885  // the former. We know the ranges have equal length, because
886  // they have the same number of local entries.
887  return std::equal (lhsElts.begin (), lhsElts.end (), rhsElts.begin ());
888  }
889  }
890  }
891  }
892 
893  template <class LocalOrdinal, class GlobalOrdinal, class Node>
894  bool
897  {
898  using Teuchos::outArg;
899  using Teuchos::REDUCE_MIN;
900  using Teuchos::reduceAll;
901  //
902  // Tests that avoid the Boolean all-reduce below by using
903  // globally consistent quantities.
904  //
905  if (this == &map) {
906  // Pointer equality on one process always implies pointer
907  // equality on all processes, since Map is immutable.
908  return true;
909  }
910  else if (getComm ()->getSize () != map.getComm ()->getSize ()) {
911  // The two communicators have different numbers of processes.
912  // It's not correct to call isSameAs() in that case. This
913  // may result in the all-reduce hanging below.
914  return false;
915  }
916  else if (getGlobalNumElements () != map.getGlobalNumElements ()) {
917  // Two Maps are definitely NOT the same if they have different
918  // global numbers of indices.
919  return false;
920  }
921  else if (getMinAllGlobalIndex () != map.getMinAllGlobalIndex () ||
923  getIndexBase () != map.getIndexBase ()) {
924  // If the global min or max global index doesn't match, or if
925  // the index base doesn't match, then the Maps aren't the same.
926  return false;
927  }
928  else if (isDistributed () != map.isDistributed ()) {
929  // One Map is distributed and the other is not, which means that
930  // the Maps aren't the same.
931  return false;
932  }
933  else if (isContiguous () && isUniform () &&
934  map.isContiguous () && map.isUniform ()) {
935  // Contiguous uniform Maps with the same number of processes in
936  // their communicators, with the same global numbers of indices,
937  // and with matching index bases and ranges, must be the same.
938  return true;
939  }
940 
941  // The two communicators must have the same number of processes,
942  // with process ranks occurring in the same order. This uses
943  // MPI_COMM_COMPARE. The MPI 3.1 standard (Section 6.4) says:
944  // "Operations that access communicators are local and their
945  // execution does not require interprocess communication."
946  // However, just to be sure, I'll put this call after the above
947  // tests that don't communicate.
948  if (! Details::congruent (*comm_, * (map.getComm ()))) {
949  return false;
950  }
951 
952  // If we get this far, we need to check local properties and then
953  // communicate local sameness across all processes.
954  const int isSame_lcl = locallySameAs (map) ? 1 : 0;
955 
956  // Return true if and only if all processes report local sameness.
957  int isSame_gbl = 0;
958  reduceAll<int, int> (*comm_, REDUCE_MIN, isSame_lcl, outArg (isSame_gbl));
959  return isSame_gbl == 1;
960  }
961 
962  template <class LocalOrdinal, class GlobalOrdinal, class Node>
963  Teuchos::ArrayView<const GlobalOrdinal>
965  {
966  typedef GlobalOrdinal GO; // convenient abbreviation
967  typedef Kokkos::View<GO*, device_type> lg_view_type;
968 
969  // If the local-to-global mapping doesn't exist yet, and if we
970  // have local entries, then create and fill the local-to-global
971  // mapping.
972  const bool needToCreateLocalToGlobalMapping =
973  lgMap_.dimension_0 () == 0 && numLocalElements_ > 0;
974 
975  if (needToCreateLocalToGlobalMapping) {
976 #ifdef HAVE_TEUCHOS_DEBUG
977  // The local-to-global mapping should have been set up already
978  // for a noncontiguous map.
979  TEUCHOS_TEST_FOR_EXCEPTION( ! isContiguous(), std::logic_error,
980  "Tpetra::Map::getNodeElementList: The local-to-global mapping (lgMap_) "
981  "should have been set up already for a noncontiguous Map. Please report"
982  " this bug to the Tpetra team.");
983 #endif // HAVE_TEUCHOS_DEBUG
984 
985  typedef typename Teuchos::ArrayRCP<GO>::size_type size_type;
986  const size_type numElts = static_cast<size_type> (getNodeNumElements ());
987 
988  lg_view_type lgMap ("lgMap", numElts);
989  if (numElts != 0) {
990  auto lgMap_host = Kokkos::create_mirror_view (lgMap);
991  GO gid = minMyGID_;
992  for (size_type k = 0; k < numElts; ++k, ++gid) {
993  lgMap_host[k] = gid;
994  }
995  // We filled lgMap on host; now, sync it back to device.
996  Kokkos::deep_copy (lgMap, lgMap_host);
997  }
998 
999  // "Commit" the local-to-global lookup table we filled in above.
1000  lgMap_ = lgMap;
1001  }
1002 
1003  // NOTE (mfh 12 Jan 2016) This assumes UVM, if lgMap is a CUDA
1004  // device View.
1005  const GO* lgMapHostRawPtr = lgMap_.ptr_on_device ();
1006  // The third argument forces ArrayView not to try to track memory
1007  // in a debug build. We have to use it because the memory does
1008  // not belong to a Teuchos memory management class.
1009  return Teuchos::ArrayView<const GO> (lgMapHostRawPtr, lgMap_.dimension_0 (),
1010  Teuchos::RCP_DISABLE_NODE_LOOKUP);
1011  }
1012 
1013  template <class LocalOrdinal, class GlobalOrdinal, class Node>
1015  return distributed_;
1016  }
1017 
1018  template <class LocalOrdinal, class GlobalOrdinal, class Node>
1020  using Teuchos::TypeNameTraits;
1021  std::ostringstream os;
1022 
1023  os << "Tpetra::Map: {"
1024  << "LocalOrdinalType: " << TypeNameTraits<LocalOrdinal>::name ()
1025  << ", GlobalOrdinalType: " << TypeNameTraits<GlobalOrdinal>::name ()
1026  << ", NodeType: " << TypeNameTraits<Node>::name ();
1027  if (this->getObjectLabel () != "") {
1028  os << ", Label: \"" << this->getObjectLabel () << "\"";
1029  }
1030  os << ", Global number of entries: " << getGlobalNumElements ()
1031  << ", Number of processes: " << getComm ()->getSize ()
1032  << ", Uniform: " << (isUniform () ? "true" : "false")
1033  << ", Contiguous: " << (isContiguous () ? "true" : "false")
1034  << ", Distributed: " << (isDistributed () ? "true" : "false")
1035  << "}";
1036  return os.str ();
1037  }
1038 
1039  template <class LocalOrdinal, class GlobalOrdinal, class Node>
1040  void
1042  describe (Teuchos::FancyOStream &out,
1043  const Teuchos::EVerbosityLevel verbLevel) const
1044  {
1045  using std::endl;
1046  using std::setw;
1047  using Teuchos::ArrayView;
1048  using Teuchos::as;
1049  using Teuchos::OSTab;
1050  using Teuchos::toString;
1051  using Teuchos::TypeNameTraits;
1052  using Teuchos::VERB_DEFAULT;
1053  using Teuchos::VERB_NONE;
1054  using Teuchos::VERB_LOW;
1055  using Teuchos::VERB_MEDIUM;
1056  using Teuchos::VERB_HIGH;
1057  using Teuchos::VERB_EXTREME;
1058  typedef typename ArrayView<const GlobalOrdinal>::size_type size_type;
1059 
1060  const size_t nME = getNodeNumElements ();
1061  ArrayView<const GlobalOrdinal> myEntries = getNodeElementList ();
1062  const int myRank = comm_->getRank ();
1063  const int numProcs = comm_->getSize ();
1064 
1065  const Teuchos::EVerbosityLevel vl = (verbLevel == VERB_DEFAULT) ? VERB_LOW : verbLevel;
1066 
1067  size_t width = 1;
1068  for (size_t dec=10; dec<getGlobalNumElements(); dec *= 10) {
1069  ++width;
1070  }
1071  width = std::max<size_t> (width, as<size_t> (12)) + 2;
1072 
1073  // By convention, describe() always begins with a tab before printing.
1074  OSTab tab0 (out);
1075 
1076  if (vl == VERB_NONE) {
1077  // do nothing
1078  }
1079  else if (vl == VERB_LOW) {
1080  if (myRank == 0) {
1081  out << "Tpetra::Map:" << endl;
1082  OSTab tab1 (out);
1083  out << "LocalOrdinalType: " << TypeNameTraits<LocalOrdinal>::name () << endl
1084  << "GlobalOrdinalType: " << TypeNameTraits<GlobalOrdinal>::name () << endl
1085  << "NodeType: " << TypeNameTraits<Node>::name () << endl;
1086  if (this->getObjectLabel () != "") {
1087  out << "Label: \"" << this->getObjectLabel () << "\"" << endl;
1088  }
1089  out << "Global number of entries: " << getGlobalNumElements () << endl
1090  << "Minimum global index: " << getMinAllGlobalIndex () << endl
1091  << "Maximum global index: " << getMaxAllGlobalIndex () << endl
1092  << "Index base: " << getIndexBase () << endl
1093  << "Number of processes: " << getComm ()->getSize () << endl
1094  << "Uniform: " << (isUniform () ? "true" : "false") << endl
1095  << "Contiguous: " << (isContiguous () ? "true" : "false") << endl
1096  << "Distributed: " << (isDistributed () ? "true" : "false") << endl;
1097  }
1098  }
1099 
1100  if (vl >= VERB_HIGH) { // HIGH or EXTREME
1101  for (int p = 0; p < numProcs; ++p) {
1102  if (myRank == p) {
1103  out << "Process " << myRank << ":" << endl;
1104  OSTab tab1 (out);
1105  out << "My number of entries: " << nME << endl
1106  << "My minimum global index: " << getMinGlobalIndex () << endl
1107  << "My maximum global index: " << getMaxGlobalIndex () << endl;
1108  if (vl == VERB_EXTREME) {
1109  out << "My global indices: [";
1110  for (size_type k = 0; k < myEntries.size (); ++k) {
1111  out << myEntries[k];
1112  if (k + 1 < myEntries.size ()) {
1113  out << ", ";
1114  }
1115  }
1116  out << "]" << endl;
1117  }
1118  std::flush (out);
1119  }
1120  // Do a few global ops to give I/O a chance to complete
1121  comm_->barrier ();
1122  comm_->barrier ();
1123  comm_->barrier ();
1124  }
1125  }
1126  }
1127 
1128  template <class LocalOrdinal, class GlobalOrdinal, class Node>
1129  RCP<const Map<LocalOrdinal, GlobalOrdinal, Node> >
1131  replaceCommWithSubset (const Teuchos::RCP<const Teuchos::Comm<int> >& newComm) const
1132  {
1133  using Teuchos::Comm;
1134  using Teuchos::null;
1136  using Teuchos::outArg;
1137  using Teuchos::RCP;
1138  using Teuchos::rcp;
1139  using Teuchos::REDUCE_MIN;
1140  using Teuchos::reduceAll;
1141  typedef global_size_t GST;
1142  typedef LocalOrdinal LO;
1143  typedef GlobalOrdinal GO;
1144  typedef Map<LO, GO, Node> map_type;
1145 
1146  // mfh 26 Mar 2013: The lazy way to do this is simply to recreate
1147  // the Map by calling its ordinary public constructor, using the
1148  // original Map's data. This only involves O(1) all-reduces over
1149  // the new communicator, which in the common case only includes a
1150  // small number of processes.
1151 
1152  // Make Map compute the global number of elements.
1153  const GST globalNumElts = OrdinalTraits<GST>::invalid ();
1154  ArrayView<const GO> myElts = this->getNodeElementList ();
1155  RCP<Node> node = this->getNode ();
1156 
1157  // Create the Map to return.
1158  if (newComm.is_null ()) {
1159  return null; // my process does not participate in the new Map
1160  } else {
1161  // Map requires that the index base equal the global min GID.
1162  // Figuring out the global min GID requires a reduction over all
1163  // processes in the new communicator. It could be that some (or
1164  // even all) of these processes contain zero entries. (Recall
1165  // that this method, unlike removeEmptyProcesses(), may remove
1166  // an arbitrary subset of processes.) We deal with this by
1167  // doing a min over the min GID on each process if the process
1168  // has more than zero entries, or the global max GID, if that
1169  // process has zero entries. If no processes have any entries,
1170  // then the index base doesn't matter anyway.
1171  const GO myMinGid = (this->getNodeNumElements () == 0) ?
1172  this->getMaxAllGlobalIndex () : this->getMinGlobalIndex ();
1173  GO newIndexBase = OrdinalTraits<GO>::invalid ();
1174  reduceAll<int, GO> (*newComm, REDUCE_MIN, myMinGid, outArg (newIndexBase));
1175  return rcp (new map_type (globalNumElts, myElts, newIndexBase, newComm, node));
1176  }
1177  }
1178 
1179  template <class LocalOrdinal, class GlobalOrdinal, class Node>
1180  RCP<const Map<LocalOrdinal, GlobalOrdinal, Node> >
1183  {
1184  using Teuchos::Comm;
1185  using Teuchos::null;
1186  using Teuchos::outArg;
1187  using Teuchos::RCP;
1188  using Teuchos::rcp;
1189  using Teuchos::REDUCE_MIN;
1190  using Teuchos::reduceAll;
1191 
1192  // Create the new communicator. split() returns a valid
1193  // communicator on all processes. On processes where color == 0,
1194  // ignore the result. Passing key == 0 tells MPI to order the
1195  // processes in the new communicator by their rank in the old
1196  // communicator.
1197  const int color = (numLocalElements_ == 0) ? 0 : 1;
1198  // MPI_Comm_split must be called collectively over the original
1199  // communicator. We can't just call it on processes with color
1200  // one, even though we will ignore its result on processes with
1201  // color zero.
1202  RCP<const Comm<int> > newComm = comm_->split (color, 0);
1203  if (color == 0) {
1204  newComm = null;
1205  }
1206 
1207  // Create the Map to return.
1208  if (newComm.is_null ()) {
1209  return null; // my process does not participate in the new Map
1210  } else {
1211  // The default constructor that's useful for clone() above is
1212  // also useful here.
1213  RCP<Map> map = rcp (new Map ());
1214 
1215  map->comm_ = newComm;
1216  map->indexBase_ = indexBase_;
1217  map->numGlobalElements_ = numGlobalElements_;
1218  map->numLocalElements_ = numLocalElements_;
1219  map->minMyGID_ = minMyGID_;
1220  map->maxMyGID_ = maxMyGID_;
1221  map->minAllGID_ = minAllGID_;
1222  map->maxAllGID_ = maxAllGID_;
1223  map->firstContiguousGID_= firstContiguousGID_;
1224  map->lastContiguousGID_ = lastContiguousGID_;
1225 
1226  // Uniformity and contiguity have not changed. The directory
1227  // has changed, but we've taken care of that above.
1228  map->uniform_ = uniform_;
1229  map->contiguous_ = contiguous_;
1230 
1231  // If the original Map was NOT distributed, then the new Map
1232  // cannot be distributed.
1233  //
1234  // If the number of processes in the new communicator is 1, then
1235  // the new Map is not distributed.
1236  //
1237  // Otherwise, we have to check the new Map using an all-reduce
1238  // (over the new communicator). For example, the original Map
1239  // may have had some processes with zero elements, and all other
1240  // processes with the same number of elements as in the whole
1241  // Map. That Map is technically distributed, because of the
1242  // processes with zero elements. Removing those processes would
1243  // make the new Map locally replicated.
1244  if (! distributed_ || newComm->getSize () == 1) {
1245  map->distributed_ = false;
1246  } else {
1247  const int iOwnAllGids = (numLocalElements_ == numGlobalElements_) ? 1 : 0;
1248  int allProcsOwnAllGids = 0;
1249  reduceAll<int, int> (*newComm, REDUCE_MIN, iOwnAllGids, outArg (allProcsOwnAllGids));
1250  map->distributed_ = (allProcsOwnAllGids == 1) ? false : true;
1251  }
1252 
1253  map->lgMap_ = lgMap_;
1254  map->glMap_ = glMap_;
1255  map->node_ = node_;
1256 
1257  // Map's default constructor creates an uninitialized Directory.
1258  // The Directory will be initialized on demand in
1259  // getRemoteIndexList().
1260  //
1261  // FIXME (mfh 26 Mar 2013) It should be possible to "filter" the
1262  // directory more efficiently than just recreating it. If
1263  // directory recreation proves a bottleneck, we can always
1264  // revisit this. On the other hand, Directory creation is only
1265  // collective over the new, presumably much smaller
1266  // communicator, so it may not be worth the effort to optimize.
1267 
1268  return map;
1269  }
1270  }
1271 
1272  template <class LocalOrdinal, class GlobalOrdinal, class Node>
1273  void
1275  {
1276  TEUCHOS_TEST_FOR_EXCEPTION(
1277  directory_.is_null (), std::logic_error, "Tpetra::Map::setupDirectory: "
1278  "The Directory is null. "
1279  "Please report this bug to the Tpetra developers.");
1280 
1281  // Only create the Directory if it hasn't been created yet.
1282  // This is a collective operation.
1283  if (! directory_->initialized ()) {
1284  directory_->initialize (*this);
1285  }
1286  }
1287 
1288  template <class LocalOrdinal, class GlobalOrdinal, class Node>
1289  LookupStatus
1291  getRemoteIndexList (const Teuchos::ArrayView<const GlobalOrdinal>& GIDs,
1292  const Teuchos::ArrayView<int>& PIDs,
1293  const Teuchos::ArrayView<LocalOrdinal>& LIDs) const
1294  {
1296  typedef Teuchos::ArrayView<int>::size_type size_type;
1297 
1298  // Empty Maps (i.e., containing no indices on any processes in the
1299  // Map's communicator) are perfectly valid. In that case, if the
1300  // input GID list is nonempty, we fill the output arrays with
1301  // invalid values, and return IDNotPresent to notify the caller.
1302  // It's perfectly valid to give getRemoteIndexList GIDs that the
1303  // Map doesn't own. SubmapImport test 2 needs this functionality.
1304  if (getGlobalNumElements () == 0) {
1305  if (GIDs.size () == 0) {
1306  return AllIDsPresent; // trivially
1307  } else {
1308  for (size_type k = 0; k < PIDs.size (); ++k) {
1309  PIDs[k] = OrdinalTraits<int>::invalid ();
1310  }
1311  for (size_type k = 0; k < LIDs.size (); ++k) {
1312  LIDs[k] = OrdinalTraits<LocalOrdinal>::invalid ();
1313  }
1314  return IDNotPresent;
1315  }
1316  }
1317 
1318  // getRemoteIndexList must be called collectively, and Directory
1319  // initialization is collective too, so it's OK to initialize the
1320  // Directory on demand.
1321  setupDirectory ();
1322  return directory_->getDirectoryEntries (*this, GIDs, PIDs, LIDs);
1323  }
1324 
1325  template <class LocalOrdinal, class GlobalOrdinal, class Node>
1326  LookupStatus
1328  getRemoteIndexList (const Teuchos::ArrayView<const GlobalOrdinal> & GIDs,
1329  const Teuchos::ArrayView<int> & PIDs) const
1330  {
1331  if (getGlobalNumElements () == 0) {
1332  if (GIDs.size () == 0) {
1333  return AllIDsPresent; // trivially
1334  } else {
1335  // The Map contains no indices, so all output PIDs are invalid.
1336  for (Teuchos::ArrayView<int>::size_type k = 0; k < PIDs.size (); ++k) {
1338  }
1339  return IDNotPresent;
1340  }
1341  }
1342 
1343  // getRemoteIndexList must be called collectively, and Directory
1344  // initialization is collective too, so it's OK to initialize the
1345  // Directory on demand.
1346  setupDirectory ();
1347  return directory_->getDirectoryEntries (*this, GIDs, PIDs);
1348  }
1349 
1350  template <class LocalOrdinal, class GlobalOrdinal, class Node>
1351  Teuchos::RCP<const Teuchos::Comm<int> >
1353  return comm_;
1354  }
1355 
1356  template <class LocalOrdinal, class GlobalOrdinal, class Node>
1357  Teuchos::RCP<Node>
1359  return node_;
1360  }
1361 
1362  template <class LocalOrdinal,class GlobalOrdinal, class Node>
1364  using Teuchos::as;
1365  using Teuchos::outArg;
1366  using Teuchos::REDUCE_MIN;
1367  using Teuchos::reduceAll;
1368 
1369  bool global = false;
1370  if (comm_->getSize () > 1) {
1371  // The communicator has more than one process, but that doesn't
1372  // necessarily mean the Map is distributed.
1373  int localRep = 0;
1374  if (numGlobalElements_ == as<global_size_t> (numLocalElements_)) {
1375  // The number of local elements on this process equals the
1376  // number of global elements.
1377  //
1378  // NOTE (mfh 22 Nov 2011) Does this still work if there were
1379  // duplicates in the global ID list on input (the third Map
1380  // constructor), so that the number of local elements (which
1381  // are not duplicated) on this process could be less than the
1382  // number of global elements, even if this process owns all
1383  // the elements?
1384  localRep = 1;
1385  }
1386  int allLocalRep;
1387  reduceAll<int, int> (*comm_, REDUCE_MIN, localRep, outArg (allLocalRep));
1388  if (allLocalRep != 1) {
1389  // At least one process does not own all the elements.
1390  // This makes the Map a distributed Map.
1391  global = true;
1392  }
1393  }
1394  // If the communicator has only one process, then the Map is not
1395  // distributed.
1396  return global;
1397  }
1398 
1399 } // Tpetra namespace
1400 
1401 template <class LocalOrdinal, class GlobalOrdinal>
1402 Teuchos::RCP< const Tpetra::Map<LocalOrdinal,GlobalOrdinal> >
1403 Tpetra::createLocalMap(size_t numElements, const Teuchos::RCP< const Teuchos::Comm< int > > &comm) {
1404  typedef LocalOrdinal LO;
1405  typedef GlobalOrdinal GO;
1406  typedef typename ::Tpetra::Map<LO, GO>::node_type NT;
1407  return createLocalMapWithNode<LO, GO> (numElements, comm, KokkosClassic::Details::getNode<NT> ());
1408 }
1409 
1410 template <class LocalOrdinal, class GlobalOrdinal>
1411 Teuchos::RCP< const Tpetra::Map<LocalOrdinal,GlobalOrdinal> >
1412 Tpetra::createUniformContigMap(global_size_t numElements, const Teuchos::RCP< const Teuchos::Comm< int > > &comm) {
1413  typedef LocalOrdinal LO;
1414  typedef GlobalOrdinal GO;
1415  typedef typename ::Tpetra::Map<LO, GO>::node_type NT;
1416  return createUniformContigMapWithNode<LO, GO> (numElements, comm, KokkosClassic::Details::getNode<NT> ());
1417 }
1418 
1419 template <class LocalOrdinal, class GlobalOrdinal, class Node>
1420 Teuchos::RCP< const Tpetra::Map<LocalOrdinal,GlobalOrdinal,Node> >
1422  const Teuchos::RCP<const Teuchos::Comm<int> >& comm,
1423  const Teuchos::RCP<Node>& node)
1424 {
1425  using Teuchos::rcp;
1427  const GlobalOrdinal indexBase = static_cast<GlobalOrdinal> (0);
1428 
1429  return rcp (new map_type (numElements, indexBase, comm, GloballyDistributed, node));
1430 }
1431 
1432 template <class LocalOrdinal, class GlobalOrdinal, class Node>
1433 Teuchos::RCP< const Tpetra::Map<LocalOrdinal,GlobalOrdinal,Node> >
1434 Tpetra::createLocalMapWithNode (size_t numElements,
1435  const Teuchos::RCP<const Teuchos::Comm<int> >& comm,
1436  const Teuchos::RCP<Node>& node)
1437 {
1438  using Tpetra::global_size_t;
1439  using Teuchos::rcp;
1441  const GlobalOrdinal indexBase = static_cast<GlobalOrdinal> (0);
1442  const global_size_t globalNumElts = static_cast<global_size_t> (numElements);
1443 
1444  return rcp (new map_type (globalNumElts, indexBase, comm, LocallyReplicated, node));
1445 }
1446 
1447 template <class LocalOrdinal, class GlobalOrdinal, class Node>
1448 Teuchos::RCP< const Tpetra::Map<LocalOrdinal,GlobalOrdinal,Node> >
1450  size_t localNumElements,
1451  const Teuchos::RCP<const Teuchos::Comm<int> >& comm,
1452  const Teuchos::RCP<Node>& node)
1453 {
1454  using Teuchos::rcp;
1456  const GlobalOrdinal indexBase = static_cast<GlobalOrdinal> (0);
1457 
1458  return rcp (new map_type (numElements, localNumElements, indexBase, comm, node));
1459 }
1460 
1461 template <class LocalOrdinal, class GlobalOrdinal>
1462 Teuchos::RCP< const Tpetra::Map<LocalOrdinal,GlobalOrdinal> >
1463 Tpetra::createContigMap(Tpetra::global_size_t numElements, size_t localNumElements, const Teuchos::RCP< const Teuchos::Comm< int > > &comm) {
1464  return Tpetra::createContigMapWithNode<LocalOrdinal,GlobalOrdinal>(numElements, localNumElements, comm, KokkosClassic::DefaultNode::getDefaultNode() );
1465 }
1466 
1467 
1468 template <class LocalOrdinal, class GlobalOrdinal>
1469 Teuchos::RCP< const Tpetra::Map<LocalOrdinal,GlobalOrdinal> >
1470 Tpetra::createNonContigMap(const Teuchos::ArrayView<const GlobalOrdinal> &elementList,
1471  const Teuchos::RCP<const Teuchos::Comm<int> > &comm)
1472 {
1473  return Tpetra::createNonContigMapWithNode<LocalOrdinal,GlobalOrdinal>(elementList, comm, KokkosClassic::DefaultNode::getDefaultNode() );
1474 }
1475 
1476 
1477 template <class LocalOrdinal, class GlobalOrdinal, class Node>
1478 Teuchos::RCP< const Tpetra::Map<LocalOrdinal,GlobalOrdinal,Node> >
1479 Tpetra::createNonContigMapWithNode(const Teuchos::ArrayView<const GlobalOrdinal> &elementList,
1480  const Teuchos::RCP<const Teuchos::Comm<int> > &comm,
1481  const Teuchos::RCP<Node> &node)
1482 {
1483  using Teuchos::rcp;
1485  typedef Tpetra::global_size_t GST;
1486  return rcp (new map_type (Tpetra::Details::OrdinalTraits<GST>::invalid (),
1487  elementList,
1488  static_cast<GST> (0),
1489  comm,
1490  node));
1491 }
1492 
1493 template <class LocalOrdinal, class GlobalOrdinal, class Node>
1494 Teuchos::RCP< const Tpetra::Map<LocalOrdinal,GlobalOrdinal,Node> >
1496  const Teuchos::RCP< const Teuchos::Comm< int > > &comm, const Teuchos::RCP< Node > &node) {
1497  Teuchos::RCP< Tpetra::Map<LocalOrdinal,GlobalOrdinal,Node> > map;
1498  int sumOfWeights, elemsLeft, localNumElements;
1499  const int numImages = comm->getSize(),
1500  myImageID = comm->getRank();
1501  Teuchos::reduceAll<int>(*comm,Teuchos::REDUCE_SUM,myWeight,Teuchos::outArg(sumOfWeights));
1502  const double myShare = ((double)myWeight) / ((double)sumOfWeights);
1503  localNumElements = (int)std::floor( myShare * ((double)numElements) );
1504  // std::cout << "numElements: " << numElements << " myWeight: " << myWeight << " sumOfWeights: " << sumOfWeights << " myShare: " << myShare << std::endl;
1505  Teuchos::reduceAll<int>(*comm,Teuchos::REDUCE_SUM,localNumElements,Teuchos::outArg(elemsLeft));
1506  elemsLeft = numElements - elemsLeft;
1507  // std::cout << "(before) localNumElements: " << localNumElements << " elemsLeft: " << elemsLeft << std::endl;
1508  // i think this is true. just test it for now.
1509  TEUCHOS_TEST_FOR_EXCEPT(elemsLeft < -numImages || numImages < elemsLeft);
1510  if (elemsLeft < 0) {
1511  // last elemsLeft nodes lose an element
1512  if (myImageID >= numImages-elemsLeft) --localNumElements;
1513  }
1514  else if (elemsLeft > 0) {
1515  // first elemsLeft nodes gain an element
1516  if (myImageID < elemsLeft) ++localNumElements;
1517  }
1518  // std::cout << "(after) localNumElements: " << localNumElements << std::endl;
1519  return createContigMapWithNode<LocalOrdinal,GlobalOrdinal,Node>(numElements,localNumElements,comm,node);
1520 
1521 }
1522 
1523 
1524 template<class LO, class GO, class NT>
1525 Teuchos::RCP<const Tpetra::Map<LO, GO, NT> >
1526 Tpetra::createOneToOne (const Teuchos::RCP<const Tpetra::Map<LO, GO, NT> >& M)
1527 {
1528  using Teuchos::Array;
1529  using Teuchos::ArrayView;
1530  using Teuchos::as;
1531  using Teuchos::rcp;
1532  typedef Tpetra::Map<LO, GO, NT> map_type;
1533  typedef global_size_t GST;
1535  const int myRank = M->getComm ()->getRank ();
1536 
1537  // Bypasses for special cases where either M is known to be
1538  // one-to-one, or the one-to-one version of M is easy to compute.
1539  // This is why we take M as an RCP, not as a const reference -- so
1540  // that we can return M itself if it is 1-to-1.
1541  if (! M->isDistributed ()) {
1542  // For a locally replicated Map, we assume that users want to push
1543  // all the GIDs to Process 0.
1544 
1545  // mfh 05 Nov 2013: getGlobalNumElements() does indeed return what
1546  // you think it should return, in this special case of a locally
1547  // replicated contiguous Map.
1548  const GST numGlobalEntries = M->getGlobalNumElements ();
1549  if (M->isContiguous ()) {
1550  const size_t numLocalEntries =
1551  (myRank == 0) ? as<size_t> (numGlobalEntries) : static_cast<size_t> (0);
1552  return rcp (new map_type (numGlobalEntries, numLocalEntries,
1553  M->getIndexBase (), M->getComm (),
1554  M->getNode ()));
1555  }
1556  else {
1557  ArrayView<const GO> myGids =
1558  (myRank == 0) ? M->getNodeElementList () : Teuchos::null;
1559  return rcp (new map_type (GINV, myGids (), M->getIndexBase (),
1560  M->getComm (), M->getNode ()));
1561 
1562  }
1563  }
1564  else if (M->isContiguous ()) {
1565  // Contiguous, distributed Maps are one-to-one by construction.
1566  // (Locally replicated Maps can be contiguous.)
1567  return M;
1568  }
1569  else {
1571  const size_t numMyElems = M->getNodeNumElements ();
1572  ArrayView<const GO> myElems = M->getNodeElementList ();
1573  Array<int> owner_procs_vec (numMyElems);
1574 
1575  directory.getDirectoryEntries (*M, myElems, owner_procs_vec ());
1576 
1577  Array<GO> myOwned_vec (numMyElems);
1578  size_t numMyOwnedElems = 0;
1579  for (size_t i = 0; i < numMyElems; ++i) {
1580  const GO GID = myElems[i];
1581  const int owner = owner_procs_vec[i];
1582 
1583  if (myRank == owner) {
1584  myOwned_vec[numMyOwnedElems++] = GID;
1585  }
1586  }
1587  myOwned_vec.resize (numMyOwnedElems);
1588 
1589  return rcp (new map_type (GINV, myOwned_vec (), M->getIndexBase (),
1590  M->getComm (), M->getNode ()));
1591  }
1592 }
1593 
1594 template<class LocalOrdinal, class GlobalOrdinal, class Node>
1595 Teuchos::RCP<const Tpetra::Map<LocalOrdinal,GlobalOrdinal,Node> >
1598 {
1599  using Teuchos::Array;
1600  using Teuchos::ArrayView;
1601  using Teuchos::rcp;
1602  typedef LocalOrdinal LO;
1603  typedef GlobalOrdinal GO;
1604  typedef Tpetra::Map<LO,GO,Node> map_type;
1605  int myID = M->getComm()->getRank();
1606 
1607  // FIXME (mfh 20 Feb 2013) We should have a bypass for contiguous
1608  // Maps (which are 1-to-1 by construction).
1609 
1610  //Based off Epetra's one to one.
1611 
1613  directory.initialize (*M, tie_break);
1614  size_t numMyElems = M->getNodeNumElements ();
1615  ArrayView<const GO> myElems = M->getNodeElementList ();
1616  Array<int> owner_procs_vec (numMyElems);
1617 
1618  directory.getDirectoryEntries (*M, myElems, owner_procs_vec ());
1619 
1620  Array<GO> myOwned_vec (numMyElems);
1621  size_t numMyOwnedElems = 0;
1622  for (size_t i = 0; i < numMyElems; ++i) {
1623  GO GID = myElems[i];
1624  int owner = owner_procs_vec[i];
1625 
1626  if (myID == owner) {
1627  myOwned_vec[numMyOwnedElems++] = GID;
1628  }
1629  }
1630  myOwned_vec.resize (numMyOwnedElems);
1631 
1632  // FIXME (mfh 08 May 2014) The above Directory should be perfectly
1633  // valid for the new Map. Why can't we reuse it?
1634  const global_size_t GINV =
1636  return rcp (new map_type (GINV, myOwned_vec (), M->getIndexBase (),
1637  M->getComm (), M->getNode ()));
1638 }
1639 
1640 //
1641 // Explicit instantiation macro
1642 //
1643 // Must be expanded from within the Tpetra namespace!
1644 //
1645 
1647 #define TPETRA_MAP_INSTANT(LO,GO,NODE) \
1648  \
1649  template class Map< LO , GO , NODE >; \
1650  \
1651  template Teuchos::RCP< const Map<LO,GO,NODE> > \
1652  createLocalMapWithNode<LO,GO,NODE>(size_t numElements, const Teuchos::RCP< const Teuchos::Comm< int > > &comm, const Teuchos::RCP< NODE > &node); \
1653  \
1654  template Teuchos::RCP< const Map<LO,GO,NODE> > \
1655  createContigMapWithNode<LO,GO,NODE>(global_size_t numElements, size_t localNumElements, \
1656  const Teuchos::RCP< const Teuchos::Comm< int > > &comm, const Teuchos::RCP< NODE > &node); \
1657  \
1658  template Teuchos::RCP< const Map<LO,GO,NODE> > \
1659  createNonContigMapWithNode(const Teuchos::ArrayView<const GO> &elementList, \
1660  const RCP<const Teuchos::Comm<int> > &comm, \
1661  const RCP<NODE> &node); \
1662  template Teuchos::RCP< const Map<LO,GO,NODE> > \
1663  createUniformContigMapWithNode<LO,GO,NODE>(global_size_t numElements, \
1664  const Teuchos::RCP< const Teuchos::Comm< int > > &comm, const Teuchos::RCP< NODE > &node); \
1665  \
1666  template Teuchos::RCP< const Map<LO,GO,NODE> > \
1667  createWeightedContigMapWithNode<LO,GO,NODE>(int thisNodeWeight, global_size_t numElements, \
1668  const Teuchos::RCP< const Teuchos::Comm< int > > &comm, const Teuchos::RCP< NODE > &node); \
1669  \
1670  template Teuchos::RCP<const Map<LO,GO,NODE> > \
1671  createOneToOne (const Teuchos::RCP<const Map<LO,GO,NODE> > &M); \
1672  \
1673  template Teuchos::RCP<const Map<LO,GO,NODE> > \
1674  createOneToOne (const Teuchos::RCP<const Map<LO,GO,NODE> > &M, \
1675  const Tpetra::Details::TieBreak<LO,GO> & tie_break);
1676 
1677 
1679 #define TPETRA_MAP_INSTANT_DEFAULTNODE(LO,GO) \
1680  template Teuchos::RCP< const Map<LO,GO> > \
1681  createLocalMap<LO,GO>( size_t, const Teuchos::RCP< const Teuchos::Comm< int > > &); \
1682  \
1683  template Teuchos::RCP< const Map<LO,GO> > \
1684  createContigMap<LO,GO>( global_size_t, size_t, \
1685  const Teuchos::RCP< const Teuchos::Comm< int > > &); \
1686  \
1687  template Teuchos::RCP< const Map<LO,GO> > \
1688  createNonContigMap(const Teuchos::ArrayView<const GO> &, \
1689  const RCP<const Teuchos::Comm<int> > &); \
1690  \
1691  template Teuchos::RCP< const Map<LO,GO> > \
1692  createUniformContigMap<LO,GO>( global_size_t, \
1693  const Teuchos::RCP< const Teuchos::Comm< int > > &); \
1694 
1695 #endif // TPETRA_MAP_DEF_HPP
Interface for breaking ties in ownership.
bool congruent(const Teuchos::Comm< int > &comm1, const Teuchos::Comm< int > &comm2)
Whether the two communicators are congruent.
Definition: Tpetra_Util.cpp:65
Namespace Tpetra contains the class and methods constituting the Tpetra library.
~Map()
Destructor.
GlobalOrdinal getMinGlobalIndex() const
The minimum global index owned by the calling process.
bool isNodeGlobalElement(GlobalOrdinal globalIndex) const
Whether the given global index is owned by this Map on the calling process.
KOKKOS_INLINE_FUNCTION ValueType get(const KeyType &key) const
Get the value corresponding to the given key.
Teuchos::RCP< const Map< LocalOrdinal, GlobalOrdinal > > createNonContigMap(const ArrayView< const GlobalOrdinal > &elementList, const RCP< const Teuchos::Comm< int > > &comm)
Non-member constructor for a non-contiguous Map with the default Kokkos Node.
bool isContiguous() const
True if this Map is distributed contiguously, else false.
LookupStatus
Return status of Map remote index lookup (getRemoteIndexList()).
Teuchos::RCP< const Map< LocalOrdinal, GlobalOrdinal, Node > > createLocalMapWithNode(size_t numElements, const Teuchos::RCP< const Teuchos::Comm< int > > &comm, const Teuchos::RCP< Node > &node=defaultArgNode< Node >())
Nonmember constructor for a locally replicated Map with a specified Kokkos Node.
bool isCompatible(const Map< LocalOrdinal, GlobalOrdinal, Node > &map) const
True if and only if map is compatible with this Map.
bool isUniform() const
Whether the range of global indices is uniform.
Teuchos::RCP< const Map< LocalOrdinal, GlobalOrdinal, Node > > createContigMapWithNode(global_size_t numElements, size_t localNumElements, const Teuchos::RCP< const Teuchos::Comm< int > > &comm, const Teuchos::RCP< Node > &node=defaultArgNode< Node >())
Non-member constructor for a (potentially) non-uniformly distributed, contiguous Map with a user-spec...
GlobalOrdinal getIndexBase() const
The index base for this Map.
bool isDistributed() const
Whether this Map is globally distributed or locally replicated.
LocalOrdinal getMinLocalIndex() const
The minimum local index.
Teuchos::RCP< const Teuchos::Comm< int > > getComm() const
Accessors for the Teuchos::Comm and Kokkos Node objects.
void deep_copy(const LittleBlock< ST2, LO > &dst, const LittleBlock< ST1, LO > &src, typename std::enable_if< std::is_convertible< ST1, ST2 >::value &&!std::is_const< ST2 >::value, int >::type *=NULL)
Copy the LittleBlock src into the LittleBlock dst.
GlobalOrdinal getMinAllGlobalIndex() const
The minimum global index over all processes in the communicator.
bool locallySameAs(const Map< LocalOrdinal, GlobalOrdinal, node_type > &map) const
Is the given Map locally the same as the input Map?
Teuchos::RCP< const Map< LocalOrdinal, GlobalOrdinal > > createLocalMap(size_t numElements, const Teuchos::RCP< const Teuchos::Comm< int > > &comm)
Nonmember constructor for a locally replicated Map with the default Kokkos Node.
Details::LocalMap< LocalOrdinal, GlobalOrdinal, device_type > local_map_type
Type of the "local" Map.
bool isNodeLocalElement(LocalOrdinal localIndex) const
Whether the given local index is valid for this Map on the calling process.
"Local" part of Map suitable for Kokkos kernels.
Teuchos::RCP< const Map< LocalOrdinal, GlobalOrdinal, Node > > createWeightedContigMapWithNode(int thisNodeWeight, global_size_t numElements, const Teuchos::RCP< const Teuchos::Comm< int > > &comm, const Teuchos::RCP< Node > &node)
Non-member constructor for a contiguous Map with user-defined weights and a user-specified Kokkos Nod...
Implementation details of Tpetra.
GlobalOrdinal getMaxAllGlobalIndex() const
The maximum global index over all processes in the communicator.
size_t global_size_t
Global size_t object.
Traits class for "invalid" (flag) values of integer types that Tpetra uses as local ordinals or globa...
Teuchos::RCP< const Map< LocalOrdinal, GlobalOrdinal > > createUniformContigMap(global_size_t numElements, const Teuchos::RCP< const Teuchos::Comm< int > > &comm)
Non-member constructor for a uniformly distributed, contiguous Map with the default Kokkos Node...
Teuchos::RCP< const Map< LocalOrdinal, GlobalOrdinal, Node > > createOneToOne(const Teuchos::RCP< const Map< LocalOrdinal, GlobalOrdinal, Node > > &M)
Creates a one-to-one version of the given Map where each GID is owned by only one process...
RCP< const Map< LocalOrdinal, GlobalOrdinal, Node > > removeEmptyProcesses() const
Return a new Map with processes with zero elements removed.
GlobalOrdinal getGlobalElement(LocalOrdinal localIndex) const
The global index corresponding to the given local index.
Teuchos::RCP< Node > getNode() const
Get this Map&#39;s Node object.
RCP< const Map< LocalOrdinal, GlobalOrdinal, Node > > replaceCommWithSubset(const Teuchos::RCP< const Teuchos::Comm< int > > &newComm) const
Replace this Map&#39;s communicator with a subset communicator.
GlobalOrdinal getMaxGlobalIndex() const
The maximum global index owned by the calling process.
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.
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.
LocalOrdinal getLocalElement(GlobalOrdinal globalIndex) const
The local index corresponding to the given global index.
local_map_type getLocalMap() const
Get the local Map for Kokkos kernels.
Teuchos::ArrayView< const GlobalOrdinal > getNodeElementList() const
Return a view of the global indices owned by this process.
Teuchos::RCP< const Map< LocalOrdinal, GlobalOrdinal > > createContigMap(global_size_t numElements, size_t localNumElements, const Teuchos::RCP< const Teuchos::Comm< int > > &comm)
Non-member constructor for a (potentially) non-uniformly distributed, contiguous Map with the default...
size_t getNodeNumElements() const
The number of elements belonging to the calling process.
Describes a parallel distribution of objects over processes.
bool isSameAs(const Map< LocalOrdinal, GlobalOrdinal, Node > &map) const
True if and only if map is identical to this Map.
Implement mapping from global ID to process ID and local ID.
Stand-alone utility functions and macros.
bool isOneToOne() const
Whether the Map is one to one.
void initialize(const map_type &map)
Initialize the Directory with its Map.
Teuchos::RCP< const Map< LocalOrdinal, GlobalOrdinal, Node > > createNonContigMapWithNode(const ArrayView< const GlobalOrdinal > &elementList, const RCP< const Teuchos::Comm< int > > &comm, const RCP< Node > &node)
Non-member constructor for a non-contiguous Map with a user-specified Kokkos Node.
LocalGlobal
Enum for local versus global allocation of Map entries.
void describe(Teuchos::FancyOStream &out, const Teuchos::EVerbosityLevel verbLevel=Teuchos::Describable::verbLevel_default) const
Print this object with the given verbosity level to the given Teuchos::FancyOStream.
LocalOrdinal getMaxLocalIndex() const
The maximum local index on the calling process.
Teuchos::RCP< const Map< LocalOrdinal, GlobalOrdinal, Node > > createUniformContigMapWithNode(global_size_t numElements, const Teuchos::RCP< const Teuchos::Comm< int > > &comm, const Teuchos::RCP< Node > &node=defaultArgNode< Node >())
Non-member constructor for a uniformly distributed, contiguous Map with a user-specified Kokkos Node...
global_size_t getGlobalNumElements() const
The number of elements in this Map.
std::string description() const
Implementation of Teuchos::Describable.
Map()
Default constructor (that does nothing).