Tpetra parallel linear algebra  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
Tpetra_Import_def.hpp
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 
42 #ifndef TPETRA_IMPORT_DEF_HPP
43 #define TPETRA_IMPORT_DEF_HPP
44 
45 #include "Tpetra_Distributor.hpp"
46 #include "Tpetra_Map.hpp"
47 #include "Tpetra_ImportExportData.hpp"
48 #include "Tpetra_Util.hpp"
49 #include "Tpetra_Import_Util.hpp"
50 #include "Tpetra_Export.hpp"
52 #include "Tpetra_Details_DualViewUtil.hpp"
53 #include "Tpetra_Details_gathervPrint.hpp"
55 #include "Teuchos_as.hpp"
56 #ifdef HAVE_TPETRA_MMM_TIMINGS
57 #include "Teuchos_TimeMonitor.hpp"
58 #endif
59 #include <array>
60 #include <memory>
61 
62 namespace Teuchos {
63  template<class T>
64  std::string toString (const std::vector<T>& x)
65  {
66  std::ostringstream os;
67  os << "[";
68  const std::size_t N = x.size ();
69  for (std::size_t k = 0; k < N; ++k) {
70  os << x[k];
71  if (k + std::size_t (1) < N) {
72  os << ",";
73  }
74  }
75  os << "]";
76  return os.str ();
77  }
78 
79  template<class ElementType, class DeviceType>
80  std::string toString (const Kokkos::View<const ElementType*, DeviceType>& x)
81  {
82  std::ostringstream os;
83  os << "[";
84  const std::size_t N = std::size_t (x.extent (0));
85  for (std::size_t k = 0; k < N; ++k) {
86  os << x[k];
87  if (k + std::size_t (1) < N) {
88  os << ",";
89  }
90  }
91  os << "]";
92  return os.str ();
93  }
94 } // namespace Teuchos
95 
96 namespace Tpetra {
97 
98  // head: init(source, target, true, remotePIDs, Teuchos::null);
99 
100  template <class LocalOrdinal, class GlobalOrdinal, class Node>
101  void
102  Import<LocalOrdinal,GlobalOrdinal,Node>::
103  init (const Teuchos::RCP<const map_type>& source,
104  const Teuchos::RCP<const map_type>& /* target */,
105  bool useRemotePIDs,
106  Teuchos::Array<int> & remotePIDs,
107  const Teuchos::RCP<Teuchos::ParameterList>& plist)
108  {
109  using ::Tpetra::Details::ProfilingRegion;
110  using Teuchos::Array;
111  using Teuchos::null;
112  using Teuchos::Ptr;
113  using Teuchos::rcp;
114  using std::endl;
115  ProfilingRegion regionImportInit ("Tpetra::Import::init");
116 
117  std::unique_ptr<std::string> verbPrefix;
118  if (this->verbose ()) {
119  std::ostringstream os;
120  const int myRank = source->getComm ()->getRank ();
121  os << "Proc " << myRank << ": Tpetra::Import::init: ";
122  verbPrefix = std::unique_ptr<std::string> (new std::string (os.str ()));
123  os << endl;
124  this->verboseOutputStream () << os.str ();
125  }
126 
127  Array<GlobalOrdinal> remoteGIDs;
128 
129 #ifdef HAVE_TPETRA_MMM_TIMINGS
130  using Teuchos::TimeMonitor;
131  std::string label;
132  if(!plist.is_null())
133  label = plist->get("Timer Label",label);
134  std::string prefix = std::string("Tpetra ")+ label + std::string(":iport_ctor:preIData: ");
135 #else
136  (void)plist;
137 #endif
138  {
139 #ifdef HAVE_TPETRA_MMM_TIMINGS
140  auto MM(*TimeMonitor::getNewTimer(prefix));
141 #endif
142  if (this->verbose ()) {
143  std::ostringstream os;
144  os << *verbPrefix << "Call setupSamePermuteRemote" << endl;
145  this->verboseOutputStream () << os.str ();
146  }
147  setupSamePermuteRemote (remoteGIDs);
148  }
149  {
150 #ifdef HAVE_TPETRA_MMM_TIMINGS
151  prefix = std::string("Tpetra ")+ label + std::string(":iport_ctor:preSetupExport: ");
152  auto MM2(*TimeMonitor::getNewTimer(prefix));
153 #endif
154  if (source->isDistributed ()) {
155  if (this->verbose ()) {
156  std::ostringstream os;
157  os << *verbPrefix << "Call setupExport" << endl;
158  this->verboseOutputStream () << os.str ();
159  }
160  setupExport (remoteGIDs,useRemotePIDs,remotePIDs);
161  }
162  else if (this->verbose ()) {
163  std::ostringstream os;
164  os << *verbPrefix << "Source Map not distributed; skip setupExport"
165  << endl;
166  this->verboseOutputStream () << os.str ();
167  }
168  }
169 
170  TEUCHOS_ASSERT( ! this->TransferData_->permuteFromLIDs_.need_sync_device () );
171  TEUCHOS_ASSERT( ! this->TransferData_->permuteFromLIDs_.need_sync_host () );
172  TEUCHOS_ASSERT( ! this->TransferData_->permuteToLIDs_.need_sync_device () );
173  TEUCHOS_ASSERT( ! this->TransferData_->permuteToLIDs_.need_sync_host () );
174  TEUCHOS_ASSERT( ! this->TransferData_->remoteLIDs_.need_sync_device () );
175  TEUCHOS_ASSERT( ! this->TransferData_->remoteLIDs_.need_sync_host () );
176  TEUCHOS_ASSERT( ! this->TransferData_->exportLIDs_.need_sync_device () );
177  TEUCHOS_ASSERT( ! this->TransferData_->exportLIDs_.need_sync_host () );
178 
179  if (this->verbose ()) {
180  std::ostringstream os;
181  os << *verbPrefix << "Done!" << endl;
182  this->verboseOutputStream () << os.str ();
183  }
184  }
185 
186  template <class LocalOrdinal, class GlobalOrdinal, class Node>
188  Import (const Teuchos::RCP<const map_type >& source,
189  const Teuchos::RCP<const map_type >& target) :
190  base_type (source, target, Teuchos::null, Teuchos::null, "Import")
191  {
192  Teuchos::Array<int> dummy;
193 #ifdef HAVE_TPETRA_MMM_TIMINGS
194  Teuchos::RCP<Teuchos::ParameterList> mypars = rcp(new Teuchos::ParameterList);
195  mypars->set("Timer Label","Naive_tAFC");
196  init(source, target, false, dummy, mypars);
197 #else
198  init (source, target, false, dummy, Teuchos::null);
199 #endif
200  }
201 
202  template <class LocalOrdinal, class GlobalOrdinal, class Node>
204  Import (const Teuchos::RCP<const map_type>& source,
205  const Teuchos::RCP<const map_type>& target,
206  const Teuchos::RCP<Teuchos::FancyOStream>& out) :
207  base_type (source, target, out, Teuchos::null, "Import")
208  {
209  Teuchos::Array<int> dummy;
210  init (source, target, false, dummy, Teuchos::null);
211  }
212 
213  template <class LocalOrdinal, class GlobalOrdinal, class Node>
215  Import (const Teuchos::RCP<const map_type>& source,
216  const Teuchos::RCP<const map_type>& target,
217  const Teuchos::RCP<Teuchos::ParameterList>& plist) :
218  base_type (source, target, Teuchos::null, plist, "Import")
219  {
220  Teuchos::Array<int> dummy;
221  init (source, target, false, dummy, plist);
222  }
223 
224  template <class LocalOrdinal, class GlobalOrdinal, class Node>
226  Import (const Teuchos::RCP<const map_type>& source,
227  const Teuchos::RCP<const map_type>& target,
228  const Teuchos::RCP<Teuchos::FancyOStream>& out,
229  const Teuchos::RCP<Teuchos::ParameterList>& plist) :
230  base_type (source, target, out, plist, "Import")
231  {
232  Teuchos::Array<int> dummy;
233  init (source, target, false, dummy, plist);
234  }
235 
236  template <class LocalOrdinal, class GlobalOrdinal, class Node>
238  Import (const Teuchos::RCP<const map_type>& source,
239  const Teuchos::RCP<const map_type>& target,
240  Teuchos::Array<int>& remotePIDs,
241  const Teuchos::RCP<Teuchos::ParameterList>& plist) :
242  base_type (source, target, Teuchos::null, plist, "Import")
243  {
244  init (source, target, true, remotePIDs, plist);
245  }
246 
247  template <class LocalOrdinal, class GlobalOrdinal, class Node>
250  base_type (rhs)
251  {}
252 
253  template <class LocalOrdinal, class GlobalOrdinal, class Node>
256  base_type (exporter, typename base_type::reverse_tag ())
257  {}
258 
259  // cblcbl
260  // This is the "createExpert" version of the constructor to be used with pid/gid pairs obtained from
261  // reverse communication
262  template <class LocalOrdinal, class GlobalOrdinal, class Node>
264  Import (const Teuchos::RCP<const Map<LocalOrdinal, GlobalOrdinal, Node> >& source,
265  const Teuchos::RCP<const Map<LocalOrdinal, GlobalOrdinal, Node> >& target,
266  const Teuchos::ArrayView<int> & userRemotePIDs,
267  const Teuchos::ArrayView<const LocalOrdinal> & userExportLIDs,
268  const Teuchos::ArrayView<const int> & userExportPIDs,
269  const Teuchos::RCP<Teuchos::ParameterList>& plist,
270  const Teuchos::RCP<Teuchos::FancyOStream>& out) :
271  base_type (source, target, out, plist, "Import")
272  {
273  using ::Tpetra::Details::makeDualViewFromArrayView;
274  using Teuchos::arcp;
275  using Teuchos::Array;
276  using Teuchos::ArrayRCP;
277  using Teuchos::ArrayView;
278  using Teuchos::as;
279  using Teuchos::null;
280  using Teuchos::rcp;
281  using std::endl;
282  using LO = LocalOrdinal;
283  using GO = GlobalOrdinal;
284  using size_type = Teuchos::Array<int>::size_type;
285 
286  std::unique_ptr<std::string> prefix;
287  if (this->verbose ()) {
288  auto comm = source.is_null () ? Teuchos::null : source->getComm ();
289  const int myRank = comm.is_null () ? -1 : comm->getRank ();
290  std::ostringstream os;
291  os << "Proc " << myRank << ": Tpetra::Import createExpert ctor: ";
292  prefix = std::unique_ptr<std::string> (new std::string (os.str ()));
293  os << "Start" << endl;
294  this->verboseOutputStream () << os.str ();
295  }
296 
297  ArrayView<const GO> sourceGIDs = source->getNodeElementList ();
298  ArrayView<const GO> targetGIDs = target->getNodeElementList ();
299 
300  Array<GO> tRemoteGIDs;
301  if (this->verbose ()) {
302  std::ostringstream os;
303  os << *prefix << "Call setupSamePermuteRemote" << endl;
304  this->verboseOutputStream () << os.str ();
305  }
306  setupSamePermuteRemote (tRemoteGIDs);
307 
308  if (this->verbose ()) {
309  std::ostringstream os;
310  os << *prefix << "Sort & filter IDs" << endl;
311  this->verboseOutputStream () << os.str ();
312  }
313 
314  auto tRemoteLIDs = this->TransferData_->remoteLIDs_.view_host ();
315  this->TransferData_->remoteLIDs_.modify_host ();
316  Teuchos::Array<int> tRemotePIDs (userRemotePIDs);
317 
318  if (this->verbose () && this->getNumRemoteIDs () > 0 && ! source->isDistributed ()) {
319  std::ostringstream os;
320  os << *prefix << "Target Map has remote LIDs but source Map is not "
321  "distributed. Importing to a submap of the target Map." << endl;
322  this->verboseOutputStream () << os.str ();
323  }
324  // FIXME (mfh 03 Feb 2019) I don't see this as "abuse"; it's
325  // perfectly valid Petra Object Model behavior.
327  (getNumRemoteIDs () > 0 && ! source->isDistributed (),
328  std::runtime_error,
329  "::constructExpert: Target Map has remote LIDs but source Map "
330  "is not distributed. Importing to a submap of the target Map.");
331  TEUCHOS_TEST_FOR_EXCEPTION
332  (tRemotePIDs.size () != tRemoteGIDs.size () ||
333  size_t (tRemoteGIDs.size ()) != size_t (tRemoteLIDs.extent (0)),
334  std::runtime_error, "Import::Import createExpert version: "
335  "Size mismatch on userRemotePIDs, remoteGIDs, and remoteLIDs "
336  "Array's to sort3.");
337 
338  sort3 (tRemotePIDs.begin (),
339  tRemotePIDs.end (),
340  tRemoteGIDs.begin (),
341  tRemoteLIDs.data ());
342 
343  //Get rid of IDs that don't exist in SourceMap
344  size_type cnt = 0;
345  size_type indexIntoRemotePIDs = tRemotePIDs.size ();
346  for (size_type i = 0; i < indexIntoRemotePIDs; ++i) {
347  if (tRemotePIDs[i] == -1) {
348  ++cnt;
349  }
350  }
351 
352  if (cnt == 0) { // done modifying remoteLIDs_
353  this->TransferData_->remoteLIDs_.sync_device ();
354  }
355  else {
356  if (indexIntoRemotePIDs - cnt > 0) {
357  Array<GO> newRemoteGIDs(indexIntoRemotePIDs-cnt);
358  Array<LO> newRemoteLIDs(indexIntoRemotePIDs-cnt);
359  Array<int> newRemotePIDs(indexIntoRemotePIDs-cnt);
360  cnt = 0;
361  for (size_type j = 0; j < indexIntoRemotePIDs; ++j)
362  if(tRemotePIDs[j] != -1) {
363  newRemoteGIDs[cnt] = tRemoteGIDs[j];
364  newRemotePIDs[cnt] = tRemotePIDs[j];
365  newRemoteLIDs[cnt] = target->getLocalElement(tRemoteGIDs[j]);
366  ++cnt;
367  }
368  indexIntoRemotePIDs = cnt;
369  tRemoteGIDs = newRemoteGIDs;
370  tRemotePIDs = newRemotePIDs;
371  makeDualViewFromArrayView (this->TransferData_->remoteLIDs_,
372  newRemoteLIDs ().getConst (),
373  "remoteLIDs");
374  }
375  else { //valid RemoteIDs empty
376  indexIntoRemotePIDs = 0;
377  tRemoteGIDs.clear();
378  tRemotePIDs.clear();
379  this->TransferData_->remoteLIDs_ = decltype (this->TransferData_->remoteLIDs_) ();
380  }
381  }
382 
383  this->TransferData_->exportPIDs_ = Teuchos::Array<int> (userExportPIDs);
384  makeDualViewFromArrayView (this->TransferData_->exportLIDs_,
385  userExportLIDs, "exportLIDs");
386 
387  bool locallyComplete = true;
388  for (size_type i = 0; i < userExportPIDs.size () && locallyComplete; ++i) {
389  if (userExportPIDs[i] == -1) {
390  locallyComplete = false;
391  }
392  }
393  this->TransferData_->isLocallyComplete_ = locallyComplete;
394 
395  if (this->verbose ()) {
396  std::ostringstream os;
397  os << *prefix << "locallyComplete: "
398  << (locallyComplete ? "true" : "false")
399  << "; call createFromSendsAndRecvs" << endl;
400  this->verboseOutputStream () << os.str ();
401  }
402  {
403 #ifdef HAVE_TPETRA_MMM_TIMINGS
404  std::string mmm_prefix =
405  std::string("Tpetra ") + std::string(":iport_ctor:cFSAR ");
406 
407  auto MM3(*Teuchos::TimeMonitor::getNewTimer(mmm_prefix));
408 #endif
409  Distributor& distributor = this->TransferData_->distributor_;
410  distributor.createFromSendsAndRecvs (this->TransferData_->exportPIDs_, tRemotePIDs);
411  }
412 
413  TEUCHOS_ASSERT( ! this->TransferData_->permuteFromLIDs_.need_sync_device () );
414  TEUCHOS_ASSERT( ! this->TransferData_->permuteFromLIDs_.need_sync_host () );
415  TEUCHOS_ASSERT( ! this->TransferData_->permuteToLIDs_.need_sync_device () );
416  TEUCHOS_ASSERT( ! this->TransferData_->permuteToLIDs_.need_sync_host () );
417  TEUCHOS_ASSERT( ! this->TransferData_->remoteLIDs_.need_sync_device () );
418  TEUCHOS_ASSERT( ! this->TransferData_->remoteLIDs_.need_sync_host () );
419  TEUCHOS_ASSERT( ! this->TransferData_->exportLIDs_.need_sync_device () );
420  TEUCHOS_ASSERT( ! this->TransferData_->exportLIDs_.need_sync_host () );
421  }
422 
423  template <class LocalOrdinal, class GlobalOrdinal, class Node>
425  Import (const Teuchos::RCP<const map_type>& source,
426  const Teuchos::RCP<const map_type>& target,
427  const size_t numSameIDs,
428  Teuchos::Array<LocalOrdinal>& permuteToLIDs,
429  Teuchos::Array<LocalOrdinal>& permuteFromLIDs,
430  Teuchos::Array<LocalOrdinal>& remoteLIDs,
431  Teuchos::Array<LocalOrdinal>& exportLIDs,
432  Teuchos::Array<int>& exportPIDs,
433  Distributor& distributor,
434  const Teuchos::RCP<Teuchos::FancyOStream>& out,
435  const Teuchos::RCP<Teuchos::ParameterList>& plist) :
436  base_type (source, target, out, plist, "Import")
437  {
438  using ::Tpetra::Details::makeDualViewFromArrayView;
439  using std::endl;
440 
441  std::unique_ptr<std::string> prefix;
442  if (this->verbose ()) {
443  auto comm = source.is_null () ? Teuchos::null : source->getComm ();
444  const int myRank = comm.is_null () ? -1 : comm->getRank ();
445  std::ostringstream os;
446  os << "Proc " << myRank << ": Tpetra::Import export ctor: ";
447  prefix = std::unique_ptr<std::string> (new std::string (os.str ()));
448  os << "Start" << endl;
449  this->verboseOutputStream () << os.str ();
450  }
451 
452  bool locallyComplete = true;
453  for (Teuchos::Array<int>::size_type i = 0; i < exportPIDs.size (); ++i) {
454  if (exportPIDs[i] == -1) {
455  locallyComplete = false;
456  }
457  }
458  if (this->verbose ()) {
459  std::ostringstream os;
460  os << *prefix << "numSameIDs: " << numSameIDs << ", locallyComplete: "
461  << (locallyComplete ? "true" : "false") << endl;
462  this->verboseOutputStream () << os.str ();
463  }
464 
465  this->TransferData_->isLocallyComplete_ = locallyComplete;
466  this->TransferData_->numSameIDs_ = numSameIDs;
467 
468  makeDualViewFromArrayView (this->TransferData_->permuteToLIDs_,
469  permuteToLIDs ().getConst (),
470  "permuteToLIDs");
471  TEUCHOS_ASSERT( size_t (this->TransferData_->permuteToLIDs_.extent (0)) ==
472  size_t (permuteToLIDs.size ()) );
473  makeDualViewFromArrayView (this->TransferData_->permuteFromLIDs_,
474  permuteFromLIDs ().getConst (),
475  "permuteFromLIDs");
476  TEUCHOS_ASSERT( size_t (this->TransferData_->permuteFromLIDs_.extent (0)) ==
477  size_t (permuteFromLIDs.size ()) );
478  makeDualViewFromArrayView (this->TransferData_->remoteLIDs_,
479  remoteLIDs ().getConst (),
480  "remoteLIDs");
481  TEUCHOS_ASSERT( size_t (this->TransferData_->remoteLIDs_.extent (0)) ==
482  size_t (remoteLIDs.size ()) );
483  makeDualViewFromArrayView (this->TransferData_->exportLIDs_,
484  exportLIDs ().getConst (),
485  "exportLIDs");
486  TEUCHOS_ASSERT( size_t (this->TransferData_->exportLIDs_.extent (0)) ==
487  size_t (exportLIDs.size ()) );
488  this->TransferData_->exportPIDs_.swap (exportPIDs);
489  this->TransferData_->distributor_.swap (distributor);
490 
491  TEUCHOS_ASSERT( ! this->TransferData_->permuteFromLIDs_.need_sync_device () );
492  TEUCHOS_ASSERT( ! this->TransferData_->permuteFromLIDs_.need_sync_host () );
493  TEUCHOS_ASSERT( ! this->TransferData_->permuteToLIDs_.need_sync_device () );
494  TEUCHOS_ASSERT( ! this->TransferData_->permuteToLIDs_.need_sync_host () );
495  TEUCHOS_ASSERT( ! this->TransferData_->remoteLIDs_.need_sync_device () );
496  TEUCHOS_ASSERT( ! this->TransferData_->remoteLIDs_.need_sync_host () );
497  TEUCHOS_ASSERT( ! this->TransferData_->exportLIDs_.need_sync_device () );
498  TEUCHOS_ASSERT( ! this->TransferData_->exportLIDs_.need_sync_host () );
499  }
500 
501  namespace { // (anonymous)
502 
503  template <class LO, class GO, class NT>
504  struct ImportLocalSetupResult
505  {
506  Teuchos::RCP<const ::Tpetra::Map<LO, GO, NT> > targetMap;
507  LO numSameIDs;
508  // std::vector<LO> permuteToLIDs; // users aren't supposed to have permutes
509  // std::vector<LO> permuteFromLIDs; // users aren't suppoosed to have permutes
510  std::vector<GO> remoteGIDs;
511  std::vector<LO> remoteLIDs;
512  std::vector<int> remotePIDs;
513  LO numPermutes; // users aren't supposed to have permutes
514  };
515 
516  template<class T>
517  void printArray (std::ostream& out, const T x[], const std::size_t N)
518  {
519  out << "[";
520  for (std::size_t k = 0; k < N; ++k) {
521  out << x[k];
522  if (k + 1 < N) {
523  out << ", ";
524  }
525  }
526  out << "]";
527  }
528 
529  template<class LO, class GO, class NT>
530  ImportLocalSetupResult<LO, GO, NT>
531  setupSamePermuteRemoteFromUserGlobalIndexList (const ::Tpetra::Map<LO, GO, NT>& sourceMap,
532  const GO targetMapRemoteOrPermuteGlobalIndices[],
533  const int targetMapRemoteOrPermuteProcessRanks[],
534  const LO numTargetMapRemoteOrPermuteGlobalIndices,
535  const bool mayReorderTargetMapIndicesLocally,
536  Teuchos::FancyOStream* out, // only valid if verbose
537  const std::string* verboseHeader, // only valid if verbose
538  const bool verbose,
539  const bool debug)
540  {
541  using std::endl;
542  const int myRank = sourceMap.getComm ()->getRank ();
543  ImportLocalSetupResult<LO, GO, NT> result;
544 
545  if (verbose) {
546  std::ostringstream os;
547  os << *verboseHeader << "- Import::setupSPR w/ remote GIDs & PIDs: " << endl
548  << *verboseHeader << " Input GIDs: ";
549  printArray (os, targetMapRemoteOrPermuteGlobalIndices, numTargetMapRemoteOrPermuteGlobalIndices);
550  os << endl << " Input PIDs: ";
551  printArray (os, targetMapRemoteOrPermuteProcessRanks, numTargetMapRemoteOrPermuteGlobalIndices);
552  os << endl;
553  *out << os.str ();
554  }
555 
556  // In debug mode, check whether any of the input GIDs are
557  // actually in the source Map on the calling process. That's an
558  // error, because it means duplicate GIDs on the calling
559  // process. Also check if any of the input PIDs are invalid.
560  if (debug) {
561  std::vector<GO> badGIDs;
562  std::vector<int> badPIDs;
563  const Teuchos::Comm<int>& comm = * (sourceMap.getComm ());
564  const int numProcs = comm.getSize ();
565 
566  for (LO k = 0; k < numTargetMapRemoteOrPermuteGlobalIndices; ++k) {
567  const GO tgtGID = targetMapRemoteOrPermuteGlobalIndices[k];
568  if (sourceMap.isNodeGlobalElement (tgtGID)) {
569  badGIDs.push_back (tgtGID);
570  }
571  const int tgtPID = targetMapRemoteOrPermuteProcessRanks[k];
572  if (tgtPID < 0 || tgtPID >= numProcs) {
573  badPIDs.push_back (tgtPID);
574  }
575  }
576 
577  std::array<int, 2> lclStatus {{
578  badGIDs.size () == 0 ? 1 : 0,
579  badPIDs.size () == 0 ? 1 : 0
580  }};
581  std::array<int, 2> gblStatus {{0, 0}}; // output argument
582  Teuchos::reduceAll<int, int> (comm, Teuchos::REDUCE_MIN, 2,
583  lclStatus.data (), gblStatus.data ());
584  const bool good = gblStatus[0] == 1 && gblStatus[1] == 1;
585  // Don't actually print all the "bad" GIDs and/or PIDs unless
586  // in verbose mode, since there could be many of them.
587  if (verbose && gblStatus[0] != 1) {
588  std::ostringstream os;
589  os << *verboseHeader << "- Some input GIDs are already in the source Map: ";
590  printArray (os, badGIDs.data (), badGIDs.size ());
591  os << endl;
592  ::Tpetra::Details::gathervPrint (*out, os.str (), comm);
593  }
594  if (verbose && gblStatus[0] != 1) {
595  std::ostringstream os;
596  os << *verboseHeader << "- Some input PIDs are invalid: ";
597  printArray (os, badPIDs.data (), badPIDs.size ());
598  os << endl;
599  ::Tpetra::Details::gathervPrint (*out, os.str (), comm);
600  }
601 
602  if (! good) {
603  std::ostringstream os;
604  os << "Tpetra::Import constructor that takes remote GIDs and PIDs: ";
605  if (gblStatus[0] != 1) {
606  os << "Some input GIDs (global indices) are already in the source Map! ";
607  }
608  if (gblStatus[1] != 1) {
609  os << "Some input PIDs (process ranks) are invalid! ";
610  }
611  os << "Rerun with the environment variable TPETRA_VERBOSE=Tpetra::Import "
612  "to see what GIDs and/or PIDs are bad.";
613  TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument, os.str ());
614  }
615  }
616 
617  // Create list of GIDs to go into target Map. We need to copy
618  // the GIDs into this list anyway, so once we have them, we can
619  // sort the "remotes" in place.
620  const LO numLclSrcIDs = static_cast<LO> (sourceMap.getNodeNumElements ());
621  const LO numLclTgtIDs = numLclSrcIDs + numTargetMapRemoteOrPermuteGlobalIndices;
622  if (verbose) {
623  std::ostringstream os;
624  os << *verboseHeader << "- Copy source Map GIDs into target Map GID list: "
625  "numLclSrcIDs=" << numLclSrcIDs
626  << ", numTargetMapRemoteOrPermuteGlobalIndices="
627  << numTargetMapRemoteOrPermuteGlobalIndices << endl;
628  *out << os.str ();
629  }
630  std::vector<GO> tgtGIDs (numLclTgtIDs); // will go into target Map ctor
631  if (sourceMap.isContiguous ()) {
632  GO curTgtGID = sourceMap.getMinGlobalIndex ();
633  for (LO k = 0; k < numLclSrcIDs; ++k, ++curTgtGID) {
634  tgtGIDs[k] = curTgtGID;
635  }
636  }
637  else { // avoid calling getNodeElementList on a contiguous Map
638  auto srcGIDs = sourceMap.getNodeElementList (); // Teuchos::ArrayView has a different
639  for (LO k = 0; k < numLclSrcIDs; ++k) { // iterator type, so can't std::copy
640  tgtGIDs[k] = srcGIDs[k];
641  }
642  }
643  std::copy (targetMapRemoteOrPermuteGlobalIndices,
644  targetMapRemoteOrPermuteGlobalIndices + numTargetMapRemoteOrPermuteGlobalIndices,
645  tgtGIDs.begin () + numLclSrcIDs);
646 
647  // Optionally, sort input by process rank, so that remotes
648  // coming from the same process are grouped together. Only sort
649  // remote GIDs. While doing so, detect permutes (input "remote"
650  // GIDs whose rank is the same as that of the calling process).
651  //
652  // Permutes are actually an error. We normally detect them in
653  // debug mode, but if we sort, we have a nearly free opportunity
654  // to do so. We may also safely ignore permutes as duplicates.
655  //
656  // NOTE: tgtPIDs only includes remotes, not source Map entries.
657  if (verbose) {
658  std::ostringstream os;
659  os << *verboseHeader << "- Sort by PID? "
660  << (mayReorderTargetMapIndicesLocally ? "true" : "false") << endl;
661  *out << os.str ();
662  }
663  std::vector<int> tgtPIDs (targetMapRemoteOrPermuteProcessRanks,
664  targetMapRemoteOrPermuteProcessRanks + numTargetMapRemoteOrPermuteGlobalIndices);
665  result.numPermutes = 0;
666  if (mayReorderTargetMapIndicesLocally) {
667  Tpetra::sort2 (tgtPIDs.begin (), tgtPIDs.end (), tgtGIDs.begin () + numLclSrcIDs);
668  auto range = std::equal_range (tgtPIDs.begin (), tgtPIDs.end (), myRank); // binary search
669  if (range.second > range.first) {
670  result.numPermutes = static_cast<LO> (range.second - range.first);
671  }
672  }
673  else { // don't sort; linear search to count permutes
674  result.numPermutes = static_cast<LO> (std::count (tgtPIDs.begin (), tgtPIDs.end (), myRank));
675  }
676  // The _actual_ number of remotes.
677  const LO numRemotes = numTargetMapRemoteOrPermuteGlobalIndices - result.numPermutes;
678  result.numSameIDs = static_cast<LO> (sourceMap.getNodeNumElements ());
679 
680  if (verbose) {
681  std::ostringstream os;
682  os << *verboseHeader << "- numSame=" << result.numSameIDs
683  << ", numPermutes=" << result.numPermutes
684  << ", numRemotes=" << numRemotes << endl;
685  *out << os.str ();
686  }
687 
688  if (result.numPermutes == 0) {
689  if (verbose) {
690  std::ostringstream os;
691  os << *verboseHeader << "- No permutes" << endl;
692  *out << os.str ();
693  }
694  result.remoteGIDs = std::vector<GO> (tgtGIDs.begin () + numLclSrcIDs, tgtGIDs.end ());
695  result.remotePIDs.swap (tgtPIDs);
696  result.remoteLIDs.resize (numRemotes);
697  for (LO k = 0; k < numRemotes; ++k) {
698  const LO tgtLid = result.numSameIDs + k;
699  result.remoteLIDs[k] = tgtLid;
700  }
701  if (verbose) {
702  std::ostringstream os;
703  os << *verboseHeader << "- Remote GIDs: "
704  << Teuchos::toString (result.remoteGIDs) << endl;
705  os << *verboseHeader << "- Remote PIDs: "
706  << Teuchos::toString (result.remotePIDs) << endl;
707  os << *verboseHeader << "- Remote LIDs: "
708  << Teuchos::toString (result.remoteLIDs) << endl;
709  *out << os.str ();
710  }
711  }
712  else { // separate permutes from remotes
713  // This case doesn't need to be optimal; it just needs to be
714  // correct. Users really shouldn't give permutes to this
715  // Import constructor.
716  result.remoteGIDs.reserve (numRemotes);
717  result.remoteLIDs.reserve (numRemotes);
718  result.remotePIDs.reserve (numRemotes);
719  for (LO k = 0; k < numTargetMapRemoteOrPermuteGlobalIndices; ++k) {
720  const LO tgtLid = result.numSameIDs + k;
721  const GO tgtGid = tgtGIDs[numLclSrcIDs + k];
722  const int tgtPid = tgtPIDs[k];
723 
724  if (tgtPid != myRank) { // it's a remote
725  result.remoteGIDs.push_back (tgtGid);
726  result.remoteLIDs.push_back (tgtLid);
727  result.remotePIDs.push_back (tgtPid);
728  }
729  }
730  if (verbose) {
731  std::ostringstream os;
732  os << *verboseHeader << "- Some permutes" << endl;
733  *out << os.str ();
734  }
735  }
736 
737  if (sourceMap.isDistributed ()) {
738  if (verbose) {
739  std::ostringstream os;
740  os << *verboseHeader << "- Sort remotes by PID, as Import always does"
741  << endl
742  << *verboseHeader << "-- remotePIDs before: "
743  << Teuchos::toString (result.remotePIDs) << endl
744  << *verboseHeader << "-- remoteGIDs before: "
745  << Teuchos::toString (result.remoteGIDs) << endl
746  << *verboseHeader << "-- remoteLIDs before: "
747  << Teuchos::toString (result.remoteLIDs) << endl;
748  *out << os.str ();
749  }
750  // Import always sorts these, regardless of what the user wanted.
751  sort3 (result.remotePIDs.begin (),
752  result.remotePIDs.end (),
753  result.remoteGIDs.begin (),
754  result.remoteLIDs.begin ());
755  if (verbose) {
756  std::ostringstream os;
757  os << *verboseHeader << "-- remotePIDs after: "
758  << Teuchos::toString (result.remotePIDs) << endl
759  << *verboseHeader << "-- remoteGIDs after: "
760  << Teuchos::toString (result.remoteGIDs) << endl
761  << *verboseHeader << "-- remoteLIDs after: "
762  << Teuchos::toString (result.remoteLIDs) << endl;
763  std::cerr << os.str ();
764  }
765  }
766 
767  if (verbose) {
768  std::ostringstream os;
769  os << *verboseHeader << "- Make target Map" << endl;
770  *out << os.str ();
771  }
772  using ::Teuchos::rcp;
773  typedef ::Tpetra::Map<LO, GO, NT> map_type;
774  typedef ::Tpetra::global_size_t GST;
775  const GST MAP_COMPUTES_GLOBAL_COUNT = ::Teuchos::OrdinalTraits<GST>::invalid ();
776  result.targetMap = rcp (new map_type (MAP_COMPUTES_GLOBAL_COUNT,
777  tgtGIDs.data (),
778  numLclTgtIDs,
779  sourceMap.getIndexBase (),
780  sourceMap.getComm ()));
781  if (verbose) {
782  std::ostringstream os;
783  os << *verboseHeader << "- Done with sameSPR..." << endl;
784  *out << os.str ();
785  }
786  return result;
787  }
788  } // namespace (anonymous)
789 
790  template <class LocalOrdinal, class GlobalOrdinal, class Node>
792  Import (const Teuchos::RCP<const Map<LocalOrdinal, GlobalOrdinal, Node> >& sourceMap,
793  const GlobalOrdinal targetMapRemoteOrPermuteGlobalIndices[],
794  const int targetMapRemoteOrPermuteProcessRanks[],
795  const LocalOrdinal numTargetMapRemoteOrPermuteGlobalIndices,
796  const bool mayReorderTargetMapIndicesLocally,
797  const Teuchos::RCP<Teuchos::ParameterList>& plist,
798  const Teuchos::RCP<Teuchos::FancyOStream>& debugOutput) :
799  // Special case: target Map is null on base_type construction.
800  // It's worthwhile for invariants like out_ not being null.
801  // We'll set TransferData_ again below.
802  base_type (sourceMap, Teuchos::null, debugOutput, plist, "Import")
803  {
804  using ::Tpetra::Details::Behavior;
805  using ::Tpetra::Details::makeDualViewFromOwningHostView;
806  using ::Tpetra::Details::makeDualViewFromVector;
807  using ::Tpetra::Details::printDualView;
808  using ::Tpetra::Details::view_alloc_no_init;
809  using Teuchos::ArrayView;
810  using Teuchos::getFancyOStream;
811  using Teuchos::RCP;
812  using Teuchos::rcp;
813  using Teuchos::rcpFromRef;
814  using std::endl;
815  typedef LocalOrdinal LO;
816  typedef GlobalOrdinal GO;
817  typedef Node NT;
818 
819  const bool debug = Behavior::debug ("Import") ||
820  Behavior::debug ("Tpetra::Import");
821 
822  std::unique_ptr<std::string> verbPfx;
823  if (this->verbose ()) {
824  std::ostringstream os;
825  const int myRank = sourceMap->getComm ()->getRank ();
826  os << "Proc " << myRank << ": Tpetra::Import ctor from remotes: ";
827  verbPfx = std::unique_ptr<std::string> (new std::string (os.str ()));
828  os << "mayReorder=" << (mayReorderTargetMapIndicesLocally ? "true" : "false")
829  << endl;
830  this->verboseOutputStream () << os.str ();
831  }
832 
833  TEUCHOS_ASSERT( ! this->TransferData_.is_null () );
834  ImportLocalSetupResult<LO, GO, NT> localSetupResult =
835  setupSamePermuteRemoteFromUserGlobalIndexList<LO, GO, NT>
836  (*sourceMap,
837  targetMapRemoteOrPermuteGlobalIndices,
838  targetMapRemoteOrPermuteProcessRanks,
839  numTargetMapRemoteOrPermuteGlobalIndices,
840  mayReorderTargetMapIndicesLocally,
841  this->TransferData_->out_.getRawPtr (),
842  verbPfx.get (),
843  this->verbose (),
844  debug);
845 
846  // Since we invoked the base_type constructor above, we know that
847  // out_ is nonnull, so we don't have to waste time creating it
848  // again.
849  using data_type = ImportExportData<LO, GO, NT>;
850  TEUCHOS_ASSERT( ! this->TransferData_.is_null () );
851  this->TransferData_ = rcp (new data_type (sourceMap,
852  localSetupResult.targetMap,
853  this->TransferData_->out_,
854  plist));
855  this->TransferData_->numSameIDs_ = localSetupResult.numSameIDs;
856  // Skip permutes; they are user error, because they duplicate
857  // non-remote indices.
858  makeDualViewFromVector (this->TransferData_->remoteLIDs_,
859  localSetupResult.remoteLIDs,
860  "remoteLIDs");
861  // "Is locally complete" for an Import means that all target Map
862  // indices on the calling process exist on at least one process
863  // (not necessarily this one) in the source Map. For this
864  // constructor, this is true if and only if all input target PIDs
865  // are valid PIDs in the communicator.
866  //
867  // FIXME (mfh 20 Feb 2018) For now, assume this is always true.
868  this->TransferData_->isLocallyComplete_ = true;
869 
870  Teuchos::Array<GO> exportGIDs;
871  if (sourceMap->isDistributed ()) {
872  if (this->verbose ()) {
873  std::ostringstream os;
874  os << *verbPfx << "Make Distributor (createFromRecvs)" << endl;
875  this->verboseOutputStream () << os.str ();
876  }
877  ArrayView<const GO> remoteGIDs (localSetupResult.remoteGIDs.data (),
878  localSetupResult.remoteGIDs.size ());
879  ArrayView<const int> remotePIDs (localSetupResult.remotePIDs.data (),
880  localSetupResult.remotePIDs.size ());
881  // Call Distributor::createFromRecvs to turn the remote GIDs and
882  // their owning PIDs into a send-and-receive communication plan.
883  // remoteGIDs and remotePIDs are input; exportGIDs and
884  // exportPIDs are output arrays that createFromRecvs allocates.
885  Distributor& distributor = this->TransferData_->distributor_;
886  distributor.createFromRecvs (remoteGIDs,
887  remotePIDs,
888  exportGIDs,
889  this->TransferData_->exportPIDs_);
890  // Find the LIDs corresponding to the (outgoing) GIDs in
891  // exportGIDs. For sparse matrix-vector multiply, this tells
892  // the calling process how to index into the source vector to
893  // get the elements which it needs to send.
894  //
895  // NOTE (mfh 03 Mar 2014) This is now a candidate for a
896  // thread-parallel kernel, but only if using the new thread-safe
897  // Map implementation.
898  if (this->verbose ()) {
899  std::ostringstream os;
900  os << *verbPfx << "Compute exportLIDs" << endl;
901  this->verboseOutputStream () << os.str ();
902  }
903  using size_type = typename Teuchos::Array<GO>::size_type;
904  const size_type numExportIDs = exportGIDs.size ();
905 
906  typename decltype (this->TransferData_->exportLIDs_)::t_host
907  exportLIDs (view_alloc_no_init ("exportLIDs"), numExportIDs);
908  for (size_type k = 0; k < numExportIDs; ++k) {
909  exportLIDs[k] = sourceMap->getLocalElement (exportGIDs[k]);
910  }
911  makeDualViewFromOwningHostView (this->TransferData_->exportLIDs_, exportLIDs);
912  }
913 
914  if (this->verbose ()) {
915  std::ostringstream os;
916  os << *verbPfx;
917  printDualView (os, this->TransferData_->remoteLIDs_,
918  "ImportExportData::remoteLIDs_");
919  os << endl;
920  this->verboseOutputStream () << os.str ();
921  }
922  if (this->verbose ()) {
923  std::ostringstream os;
924  os << *verbPfx << "Done!" << endl;
925  this->verboseOutputStream () << os.str ();
926  }
927  }
928 
929  template <class LocalOrdinal, class GlobalOrdinal, class Node>
930  void
932  describe (Teuchos::FancyOStream& out,
933  const Teuchos::EVerbosityLevel verbLevel) const
934  {
935  // Call the base class' method. It does all the work.
936  this->describeImpl (out, "Tpetra::Import", verbLevel);
937  }
938 
939  template <class LocalOrdinal, class GlobalOrdinal, class Node>
941  print (std::ostream& os) const
942  {
943  auto out = Teuchos::getFancyOStream (Teuchos::rcpFromRef (os));
944  // "Print" traditionally meant "everything."
945  this->describe (*out, Teuchos::VERB_EXTREME);
946  }
947 
948  template <class LocalOrdinal, class GlobalOrdinal, class Node>
949  void
951  setupSamePermuteRemote (Teuchos::Array<GlobalOrdinal>& remoteGIDs)
952  {
953  using ::Tpetra::Details::makeDualViewFromOwningHostView;
954  using ::Tpetra::Details::ProfilingRegion;
955  using ::Tpetra::Details::view_alloc_no_init;
956  using Teuchos::arcp;
957  using Teuchos::Array;
958  using Teuchos::ArrayRCP;
959  using Teuchos::ArrayView;
960  using Teuchos::as;
961  using Teuchos::null;
962  typedef LocalOrdinal LO;
963  typedef GlobalOrdinal GO;
964  typedef typename ArrayView<const GO>::size_type size_type;
965  ProfilingRegion regionExport ("Tpetra::Import::setupSamePermuteRemote");
966 
967  const map_type& source = * (this->getSourceMap ());
968  const map_type& target = * (this->getTargetMap ());
969  ArrayView<const GO> sourceGIDs = source.getNodeElementList ();
970  ArrayView<const GO> targetGIDs = target.getNodeElementList ();
971 
972 #ifdef HAVE_TPETRA_DEBUG
973  ArrayView<const GO> rawSrcGids = sourceGIDs;
974  ArrayView<const GO> rawTgtGids = targetGIDs;
975 #else
976  const GO* const rawSrcGids = sourceGIDs.getRawPtr ();
977  const GO* const rawTgtGids = targetGIDs.getRawPtr ();
978 #endif // HAVE_TPETRA_DEBUG
979  const size_type numSrcGids = sourceGIDs.size ();
980  const size_type numTgtGids = targetGIDs.size ();
981  const size_type numGids = std::min (numSrcGids, numTgtGids);
982 
983  // Compute numSameIDs_: the number of initial GIDs that are the
984  // same (and occur in the same order) in both Maps. The point of
985  // numSameIDs_ is for the common case of an Import where all the
986  // overlapping GIDs are at the end of the target Map, but
987  // otherwise the source and target Maps are the same. This allows
988  // a fast contiguous copy for the initial "same IDs."
989  size_type numSameGids = 0;
990  for ( ; numSameGids < numGids && rawSrcGids[numSameGids] == rawTgtGids[numSameGids]; ++numSameGids)
991  {} // third clause of 'for' does everything
992  this->TransferData_->numSameIDs_ = numSameGids;
993 
994  // Compute permuteToLIDs_, permuteFromLIDs_, remoteGIDs, and
995  // remoteLIDs_. The first two arrays are IDs to be permuted, and
996  // the latter two arrays are IDs to be received ("imported"),
997  // called "remote" IDs.
998  //
999  // IDs to permute are in both the source and target Maps, which
1000  // means we don't have to send or receive them, but we do have to
1001  // rearrange (permute) them in general. IDs to receive are in the
1002  // target Map, but not the source Map.
1003 
1004  // Iterate over the target Map's LIDs, since we only need to do
1005  // GID -> LID lookups for the source Map.
1006  const LO LINVALID = Teuchos::OrdinalTraits<LO>::invalid ();
1007  const LO numTgtLids = as<LO> (numTgtGids);
1008  LO numPermutes = 0;
1009  for (LO tgtLid = numSameGids; tgtLid < numTgtLids; ++tgtLid) {
1010  const GO curTargetGid = rawTgtGids[tgtLid];
1011  // getLocalElement() returns LINVALID if the GID isn't in the
1012  // source Map. This saves us a lookup (which
1013  // isNodeGlobalElement() would do).
1014  const LO srcLid = source.getLocalElement (curTargetGid);
1015  if (srcLid != LINVALID) { // if source.isNodeGlobalElement (curTargetGid)
1016  ++numPermutes;
1017  }
1018  }
1019  const LO numRemotes = (numTgtLids - numSameGids) - numPermutes;
1020 
1021  using host_perm_type =
1022  typename decltype (this->TransferData_->permuteToLIDs_)::t_host;
1023  host_perm_type permuteToLIDs
1024  (view_alloc_no_init ("permuteToLIDs"), numPermutes);
1025  host_perm_type permuteFromLIDs
1026  (view_alloc_no_init ("permuteFromLIDs"), numPermutes);
1027  typename decltype (this->TransferData_->remoteLIDs_)::t_host remoteLIDs
1028  (view_alloc_no_init ("permuteFromLIDs"), numRemotes);
1029 
1030  {
1031  LO numPermutes2 = 0;
1032  LO numRemotes2 = 0;
1033  for (LO tgtLid = numSameGids; tgtLid < numTgtLids; ++tgtLid) {
1034  const GO curTargetGid = rawTgtGids[tgtLid];
1035  const LO srcLid = source.getLocalElement (curTargetGid);
1036  if (srcLid != LINVALID) {
1037  permuteToLIDs[numPermutes2] = tgtLid;
1038  permuteFromLIDs[numPermutes2] = srcLid;
1039  ++numPermutes2;
1040  }
1041  else {
1042  remoteGIDs.push_back (curTargetGid);
1043  remoteLIDs[numRemotes2] = tgtLid;
1044  ++numRemotes2;
1045  }
1046  }
1047  TEUCHOS_ASSERT( numPermutes == numPermutes2 );
1048  TEUCHOS_ASSERT( numRemotes == numRemotes2 );
1049  TEUCHOS_ASSERT( size_t (numPermutes) + remoteGIDs.size () == size_t (numTgtLids - numSameGids) );
1050  }
1051 
1052  makeDualViewFromOwningHostView (this->TransferData_->permuteToLIDs_, permuteToLIDs);
1053  makeDualViewFromOwningHostView (this->TransferData_->permuteFromLIDs_, permuteFromLIDs);
1054  makeDualViewFromOwningHostView (this->TransferData_->remoteLIDs_, remoteLIDs);
1055  if (remoteLIDs.extent (0) != 0 && ! source.isDistributed ()) {
1056  // This Import has remote LIDs, meaning that the target Map has
1057  // entries on this process that are not in the source Map on
1058  // this process. However, the source Map is not distributed
1059  // globally. This implies that this Import is not locally
1060  // complete on this process.
1061  this->TransferData_->isLocallyComplete_ = false;
1062  // mfh 12 Sep 2016: I disagree that this is "abuse"; it may be
1063  // correct behavior, depending on the circumstances.
1065  (true, std::runtime_error, "::setupSamePermuteRemote(): Target has "
1066  "remote LIDs but Source is not distributed globally. Importing to a "
1067  "submap of the target map.");
1068  }
1069  }
1070 
1071 
1072  template <class LocalOrdinal, class GlobalOrdinal, class Node>
1073  void Import<LocalOrdinal,GlobalOrdinal,Node>::
1074  setupExport (Teuchos::Array<GlobalOrdinal>& remoteGIDs,
1075  bool useRemotePIDs,
1076  Teuchos::Array<int>& userRemotePIDs,
1077  const Teuchos::RCP<Teuchos::ParameterList>& plist)
1078  {
1079  using ::Tpetra::Details::makeDualViewFromOwningHostView;
1080  using ::Tpetra::Details::view_alloc_no_init;
1081  using Teuchos::Array;
1082  using Teuchos::ArrayView;
1083  using std::endl;
1084  using GO = GlobalOrdinal;
1085  typedef typename Array<int>::difference_type size_type;
1086  const char tfecfFuncName[] = "setupExport: ";
1087  const char suffix[] = " Please report this bug to the Tpetra developers.";
1088 
1089  std::unique_ptr<std::string> prefix;
1090  if (this->verbose ()) {
1091  auto srcMap = this->getSourceMap ();
1092  auto comm = srcMap.is_null () ? Teuchos::null : srcMap->getComm ();
1093  const int myRank = comm.is_null () ? -1 : comm->getRank ();
1094  std::ostringstream os;
1095  os << "Proc " << myRank << ": Tpetra::Import::setupExport: ";
1096  prefix = std::unique_ptr<std::string> (new std::string (os.str ()));
1097  os << "Start" << std::endl;
1098  this->verboseOutputStream () << os.str ();
1099  }
1100 
1101  TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC
1102  (this->getSourceMap ().is_null (), std::logic_error,
1103  "Source Map is null. " << suffix);
1104  const map_type& source = * (this->getSourceMap ());
1105 
1106  TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC
1107  (! useRemotePIDs && (userRemotePIDs.size() > 0), std::invalid_argument,
1108  "remotePIDs are non-empty but their use has not been requested.");
1109  TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC
1110  (userRemotePIDs.size () > 0 && remoteGIDs.size () != userRemotePIDs.size (),
1111  std::invalid_argument, "remotePIDs must either be of size zero or match "
1112  "the size of remoteGIDs.");
1113 
1114  // For each entry remoteGIDs[i], remoteProcIDs[i] will contain
1115  // the process ID of the process that owns that GID.
1116  ArrayView<GO> remoteGIDsView = remoteGIDs ();
1117  ArrayView<int> remoteProcIDsView;
1118 
1119  // lookup == IDNotPresent means that the source Map wasn't able to
1120  // figure out to which processes one or more of the GIDs in the
1121  // given list of remote GIDs belong.
1122  //
1123  // The previous abuse warning said "The target Map has GIDs not
1124  // found in the source Map." This statement could be confusing,
1125  // because it doesn't refer to ownership by the current process,
1126  // but rather to ownership by _any_ process participating in the
1127  // Map. (It could not possibly refer to ownership by the current
1128  // process, since remoteGIDs is exactly the list of GIDs owned by
1129  // the target Map but not owned by the source Map. It was
1130  // constructed that way by setupSamePermuteRemote().)
1131  //
1132  // What this statement means is that the source and target Maps
1133  // don't contain the same set of GIDs globally (over all
1134  // processes). That is, there is at least one GID owned by some
1135  // process in the target Map, which is not owned by _any_ process
1136  // in the source Map.
1137  Array<int> newRemotePIDs;
1138  LookupStatus lookup = AllIDsPresent;
1139 
1140  if (! useRemotePIDs) {
1141  newRemotePIDs.resize (remoteGIDsView.size ());
1142  if (this->verbose ()) {
1143  std::ostringstream os;
1144  os << *prefix << "Call sourceMap.getRemoteIndexList" << endl;
1145  this->verboseOutputStream () << os.str ();
1146  }
1147  lookup = source.getRemoteIndexList (remoteGIDsView, newRemotePIDs ());
1148  }
1149  Array<int>& remoteProcIDs = useRemotePIDs ? userRemotePIDs : newRemotePIDs;
1150 
1151  if (lookup == IDNotPresent) {
1152  // There is at least one GID owned by the calling process in the
1153  // target Map, which is not owned by any process in the source
1154  // Map.
1155  this->TransferData_->isLocallyComplete_ = false;
1156 
1157  // mfh 12 Sep 2016: I disagree that this is "abuse"; it may be
1158  // correct behavior, depending on the circumstances.
1160  (true, std::runtime_error, "::setupExport(): the source Map wasn't "
1161  "able to figure out which process owns one or more of the GIDs in the "
1162  "list of remote GIDs. This probably means that there is at least one "
1163  "GID owned by some process in the target Map which is not owned by any"
1164  " process in the source Map. (That is, the source and target Maps do "
1165  "not contain the same set of GIDs globally.)");
1166 
1167  // Ignore remote GIDs that aren't owned by any process in the
1168  // source Map. getRemoteIndexList() gives each of these a
1169  // process ID of -1.
1170 
1171  const size_type numInvalidRemote =
1172  std::count_if (remoteProcIDs.begin (), remoteProcIDs.end (),
1173  std::bind1st (std::equal_to<int> (), -1));
1174  TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC
1175  (numInvalidRemote == 0, std::logic_error, "Calling getRemoteIndexList "
1176  "on the source Map returned IDNotPresent, but none of the returned "
1177  "\"remote\" process ranks are -1. Please report this bug to the "
1178  "Tpetra developers.");
1179 
1180 #ifdef HAVE_TPETRA_MMM_TIMINGS
1181  using Teuchos::TimeMonitor;
1182  std::string label;
1183  if(!plist.is_null())
1184  label = plist->get("Timer Label",label);
1185  std::string prefix = std::string("Tpetra ")+ label + std::string(":iport_ctor:setupExport:1 ");
1186  auto MM = rcp(new TimeMonitor(*TimeMonitor::getNewTimer(prefix)));
1187 #else
1188  (void)plist;
1189 #endif
1190 
1191  // If all of them are invalid, we can delete the whole array.
1192  const size_type totalNumRemote = this->getNumRemoteIDs ();
1193  if (numInvalidRemote == totalNumRemote) {
1194  // all remotes are invalid; we have no remotes; we can delete the remotes
1195  remoteProcIDs.clear ();
1196  remoteGIDs.clear (); // invalidates remoteGIDsView
1197  this->TransferData_->remoteLIDs_ =
1198  decltype (this->TransferData_->remoteLIDs_) ();
1199  }
1200  else {
1201  // Some remotes are valid; we need to keep the valid ones.
1202  // Pack and resize remoteProcIDs, remoteGIDs, and remoteLIDs_.
1203  size_type numValidRemote = 0;
1204 #ifdef HAVE_TPETRA_DEBUG
1205  ArrayView<GO> remoteGIDsPtr = remoteGIDsView;
1206 #else
1207  GO* const remoteGIDsPtr = remoteGIDsView.getRawPtr ();
1208 #endif // HAVE_TPETRA_DEBUG
1209 
1210  // Don't mark the DualView modified, since we'll reallocate it.
1211  auto remoteLIDs = this->TransferData_->remoteLIDs_.view_host ();
1212 
1213  for (size_type r = 0; r < totalNumRemote; ++r) {
1214  // Pack in all the valid remote PIDs and GIDs.
1215  if (remoteProcIDs[r] != -1) {
1216  remoteProcIDs[numValidRemote] = remoteProcIDs[r];
1217  remoteGIDsPtr[numValidRemote] = remoteGIDsPtr[r];
1218  remoteLIDs[numValidRemote] = remoteLIDs[r];
1219  ++numValidRemote;
1220  }
1221  }
1222  TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC
1223  (numValidRemote != totalNumRemote - numInvalidRemote,
1224  std::logic_error, "After removing invalid remote GIDs and packing "
1225  "the valid remote GIDs, numValidRemote = " << numValidRemote
1226  << " != totalNumRemote - numInvalidRemote = "
1227  << totalNumRemote - numInvalidRemote
1228  << ". Please report this bug to the Tpetra developers.");
1229 
1230  remoteProcIDs.resize (numValidRemote);
1231  remoteGIDs.resize (numValidRemote);
1232 
1233  Kokkos::resize (remoteLIDs, numValidRemote);
1234  this->TransferData_->remoteLIDs_ = decltype (this->TransferData_->remoteLIDs_) ();
1235  makeDualViewFromOwningHostView (this->TransferData_->remoteLIDs_, remoteLIDs);
1236  }
1237  // Revalidate the view after clear or resize.
1238  remoteGIDsView = remoteGIDs ();
1239  }
1240 
1241  // Sort remoteProcIDs in ascending order, and apply the resulting
1242  // permutation to remoteGIDs and remoteLIDs_. This ensures that
1243  // remoteProcIDs[i], remoteGIDs[i], and remoteLIDs_[i] all refer
1244  // to the same thing.
1245  {
1246  this->TransferData_->remoteLIDs_.modify_host ();
1247  auto remoteLIDs = this->TransferData_->remoteLIDs_.view_host ();
1248  sort3 (remoteProcIDs.begin (),
1249  remoteProcIDs.end (),
1250  remoteGIDsView.getRawPtr (),
1251  remoteLIDs.data ());
1252  this->TransferData_->remoteLIDs_.sync_device ();
1253  }
1254 
1255  // Call the Distributor's createFromRecvs() method to turn the
1256  // remote GIDs and their owning processes into a send-and-receive
1257  // communication plan. remoteGIDs and remoteProcIDs_ are input;
1258  // exportGIDs and exportProcIDs_ are output arrays which are
1259  // allocated by createFromRecvs().
1260  Array<GO> exportGIDs;
1261 
1262 #ifdef HAVE_TPETRA_MMM_TIMINGS
1263  using Teuchos::TimeMonitor;
1264  std::string label;
1265  if(!plist.is_null())
1266  label = plist->get("Timer Label",label);
1267  std::string prefix2 = std::string("Tpetra ")+ label + std::string(":iport_ctor:setupExport:3 ");
1268  auto MM = rcp(new TimeMonitor(*TimeMonitor::getNewTimer(prefix2)));
1269 #endif
1270 
1271  if (this->verbose ()) {
1272  std::ostringstream os;
1273  os << *prefix << "Call createFromRecvs" << endl;
1274  this->verboseOutputStream () << endl;
1275  }
1276  this->TransferData_->distributor_.createFromRecvs (remoteGIDsView ().getConst (),
1277  remoteProcIDs, exportGIDs,
1278  this->TransferData_->exportPIDs_);
1279 
1280  // Find the LIDs corresponding to the (outgoing) GIDs in
1281  // exportGIDs. For sparse matrix-vector multiply, this tells the
1282  // calling process how to index into the source vector to get the
1283  // elements which it needs to send.
1284 #ifdef HAVE_TPETRA_MMM_TIMINGS
1285  prefix2 = std::string("Tpetra ")+ label + std::string(":iport_ctor:setupExport:4 ");
1286  MM.release();
1287  MM = rcp(new TimeMonitor(*TimeMonitor::getNewTimer(prefix2)));
1288 #endif
1289 
1290  // NOTE (mfh 03 Mar 2014) This is now a candidate for a
1291  // thread-parallel kernel, but only if using the new thread-safe
1292  // Map implementation.
1293  const size_type numExportIDs = exportGIDs.size ();
1294  if (numExportIDs > 0) {
1295  typename decltype (this->TransferData_->exportLIDs_)::t_host
1296  exportLIDs (view_alloc_no_init ("exportLIDs"), numExportIDs);
1297  ArrayView<const GO> expGIDs = exportGIDs ();
1298  for (size_type k = 0; k < numExportIDs; ++k) {
1299  exportLIDs[k] = source.getLocalElement (expGIDs[k]);
1300  }
1301  makeDualViewFromOwningHostView (this->TransferData_->exportLIDs_, exportLIDs);
1302  }
1303 
1304  if (this->verbose ()) {
1305  std::ostringstream os;
1306  os << *prefix << "Done!" << endl;
1307  this->verboseOutputStream () << os.str ();
1308  }
1309  }
1310 
1311  template <class LocalOrdinal, class GlobalOrdinal, class Node>
1312  void
1314  findUnionTargetGIDs(Teuchos::Array<GlobalOrdinal>& unionTgtGIDs,
1315  Teuchos::Array<std::pair<int,GlobalOrdinal>>& remotePGIDs,
1316  typename Teuchos::Array<GlobalOrdinal>::size_type& numSameGIDs,
1317  typename Teuchos::Array<GlobalOrdinal>::size_type& numPermuteGIDs,
1318  typename Teuchos::Array<GlobalOrdinal>::size_type& numRemoteGIDs,
1319  const Teuchos::ArrayView<const GlobalOrdinal>& sameGIDs1,
1320  const Teuchos::ArrayView<const GlobalOrdinal>& sameGIDs2,
1321  Teuchos::Array<GlobalOrdinal>& permuteGIDs1,
1322  Teuchos::Array<GlobalOrdinal>& permuteGIDs2,
1323  Teuchos::Array<GlobalOrdinal>& remoteGIDs1,
1324  Teuchos::Array<GlobalOrdinal>& remoteGIDs2,
1325  Teuchos::Array<int>& remotePIDs1,
1326  Teuchos::Array<int>& remotePIDs2) const
1327  {
1328 
1329  typedef GlobalOrdinal GO;
1330  typedef typename Teuchos::Array<GO>::size_type size_type;
1331 
1332  const size_type numSameGIDs1 = sameGIDs1.size();
1333  const size_type numSameGIDs2 = sameGIDs2.size();
1334 
1335  // Sort the permute GIDs
1336  std::sort(permuteGIDs1.begin(), permuteGIDs1.end());
1337  std::sort(permuteGIDs2.begin(), permuteGIDs2.end());
1338 
1339  // Get the union of the two target maps
1340  // Reserve the maximum possible size to guard against reallocations from
1341  // push_back operations.
1342  unionTgtGIDs.reserve(numSameGIDs1 + numSameGIDs2 +
1343  permuteGIDs1.size() + permuteGIDs2.size() +
1344  remoteGIDs1.size() + remoteGIDs2.size());
1345 
1346  // Copy the same GIDs to unionTgtGIDs. Cases for numSameGIDs1 !=
1347  // numSameGIDs2 must be treated separately.
1348  typename Teuchos::Array<GO>::iterator permuteGIDs1_end;
1349  typename Teuchos::Array<GO>::iterator permuteGIDs2_end;
1350  if (numSameGIDs2 > numSameGIDs1) {
1351 
1352  numSameGIDs = numSameGIDs2;
1353  permuteGIDs2_end = permuteGIDs2.end();
1354 
1355  // Copy the same GIDs from tgtGIDs to the union
1356  std::copy(sameGIDs2.begin(), sameGIDs2.end(), std::back_inserter(unionTgtGIDs));
1357 
1358  // Remove GIDs from permuteGIDs1 that have already been copied in to unionTgtGIDs
1359  // set_difference allows the last (output) argument to alias the first.
1360  permuteGIDs1_end = std::set_difference(permuteGIDs1.begin(), permuteGIDs1.end(),
1361  unionTgtGIDs.begin()+numSameGIDs1, unionTgtGIDs.end(),
1362  permuteGIDs1.begin());
1363 
1364  } else {
1365 
1366  numSameGIDs = numSameGIDs1;
1367  permuteGIDs1_end = permuteGIDs1.end();
1368 
1369  // Copy the same GIDs from tgtGIDs to the union
1370  std::copy(sameGIDs1.begin(), sameGIDs1.end(), std::back_inserter(unionTgtGIDs));
1371 
1372  // Remove GIDs from permuteGIDs2 that have already been copied in to unionTgtGIDs
1373  // set_difference allows the last (output) argument to alias the first.
1374  permuteGIDs2_end = std::set_difference(permuteGIDs2.begin(), permuteGIDs2.end(),
1375  unionTgtGIDs.begin()+numSameGIDs2, unionTgtGIDs.end(),
1376  permuteGIDs2.begin());
1377 
1378  }
1379 
1380  // Get the union of the permute GIDs and push it back on unionTgtGIDs
1381  std::set_union(permuteGIDs1.begin(), permuteGIDs1_end,
1382  permuteGIDs2.begin(), permuteGIDs2_end,
1383  std::back_inserter(unionTgtGIDs));
1384 
1385  // Sort the PID,GID pairs and find the unique set
1386  Teuchos::Array<std::pair<int,GO>> remotePGIDs1(remoteGIDs1.size());
1387  for (size_type k=0; k<remoteGIDs1.size(); k++)
1388  remotePGIDs1[k] = std::make_pair(remotePIDs1[k], remoteGIDs1[k]);
1389  std::sort(remotePGIDs1.begin(), remotePGIDs1.end());
1390 
1391  Teuchos::Array<std::pair<int,GO>> remotePGIDs2(remoteGIDs2.size());
1392  for (size_type k=0; k<remoteGIDs2.size(); k++)
1393  remotePGIDs2[k] = std::make_pair(remotePIDs2[k], remoteGIDs2[k]);
1394  std::sort(remotePGIDs2.begin(), remotePGIDs2.end());
1395 
1396  remotePGIDs.reserve(remotePGIDs1.size()+remotePGIDs2.size());
1397  std::merge(remotePGIDs1.begin(), remotePGIDs1.end(),
1398  remotePGIDs2.begin(), remotePGIDs2.end(),
1399  std::back_inserter(remotePGIDs));
1400  auto it = std::unique(remotePGIDs.begin(), remotePGIDs.end());
1401  remotePGIDs.resize(std::distance(remotePGIDs.begin(), it));
1402 
1403  // Finally, insert remote GIDs
1404  const size_type oldSize = unionTgtGIDs.size();
1405  unionTgtGIDs.resize(oldSize+remotePGIDs.size());
1406  for (size_type start=oldSize, k=0; k<remotePGIDs.size(); k++)
1407  unionTgtGIDs[start+k] = remotePGIDs[k].second;
1408 
1409  // Compute output only quantities
1410  numRemoteGIDs = remotePGIDs.size();
1411  numPermuteGIDs = unionTgtGIDs.size() - numSameGIDs - numRemoteGIDs;
1412 
1413  return;
1414  }
1415 
1416  template <class LocalOrdinal, class GlobalOrdinal, class Node>
1417  Teuchos::RCP<const Import<LocalOrdinal, GlobalOrdinal, Node> >
1420  {
1421  using ::Tpetra::Details::Behavior;
1422  using Teuchos::Array;
1423  using Teuchos::ArrayView;
1424  using Teuchos::as;
1425  using Teuchos::Comm;
1426  using Teuchos::RCP;
1427  using Teuchos::rcp;
1428  using Teuchos::outArg;
1429  using Teuchos::REDUCE_MIN;
1430  using Teuchos::reduceAll;
1431  using GST = Tpetra::global_size_t;
1432  using LO = LocalOrdinal;
1433  using GO = GlobalOrdinal;
1434  using import_type = Import<LO, GO, Node>;
1435  using size_type = typename Array<GO>::size_type;
1436 
1437 #ifdef HAVE_TPETRA_MMM_TIMINGS
1438  using Teuchos::TimeMonitor;
1439  std::string label = std::string("Tpetra::Import::setUnion");
1440  TimeMonitor MM(*TimeMonitor::getNewTimer(label));
1441 #endif
1442 
1443  RCP<const map_type> srcMap = this->getSourceMap ();
1444  RCP<const map_type> tgtMap1 = this->getTargetMap ();
1445  RCP<const map_type> tgtMap2 = rhs.getTargetMap ();
1446  RCP<const Comm<int> > comm = srcMap->getComm ();
1447 
1448  const bool debug = Behavior::debug ("Import::setUnion") ||
1449  Behavior::debug ("Tpetra::Import::setUnion");
1450 
1451  if (debug) {
1452  TEUCHOS_TEST_FOR_EXCEPTION
1453  (! srcMap->isSameAs (* (rhs.getSourceMap ())), std::invalid_argument,
1454  "Tpetra::Import::setUnion: The source Map of the input Import must be the "
1455  "same as (in the sense of Map::isSameAs) the source Map of this Import.");
1456  const Comm<int>& comm1 = * (tgtMap1->getComm ());
1457  const Comm<int>& comm2 = * (tgtMap2->getComm ());
1458  TEUCHOS_TEST_FOR_EXCEPTION
1459  (! ::Tpetra::Details::congruent (comm1, comm2),
1460  std::invalid_argument, "Tpetra::Import::setUnion: "
1461  "The target Maps must have congruent communicators.");
1462  }
1463 
1464  // It's probably worth the one all-reduce to check whether the two
1465  // Maps are the same. If so, we can just return a copy of *this.
1466  // isSameAs() bypasses the all-reduce if the pointers are equal.
1467  if (tgtMap1->isSameAs (*tgtMap2)) {
1468  return rcp (new import_type (*this));
1469  }
1470 
1471  // Alas, the two target Maps are not the same. That means we have
1472  // to compute their union, and the union Import object.
1473 
1474  // Get the same GIDs (same GIDs are a subview of the first numSame target
1475  // GIDs)
1476  const size_type numSameGIDs1 = this->getNumSameIDs();
1477  ArrayView<const GO> sameGIDs1 = (tgtMap1->getNodeElementList())(0,numSameGIDs1);
1478 
1479  const size_type numSameGIDs2 = rhs.getNumSameIDs();
1480  ArrayView<const GO> sameGIDs2 = (tgtMap2->getNodeElementList())(0,numSameGIDs2);
1481 
1482  // Get permute GIDs
1483  ArrayView<const LO> permuteToLIDs1 = this->getPermuteToLIDs();
1484  Array<GO> permuteGIDs1(permuteToLIDs1.size());
1485  for (size_type k=0; k<permuteGIDs1.size(); k++)
1486  permuteGIDs1[k] = tgtMap1->getGlobalElement(permuteToLIDs1[k]);
1487 
1488  ArrayView<const LO> permuteToLIDs2 = rhs.getPermuteToLIDs();
1489  Array<GO> permuteGIDs2(permuteToLIDs2.size());
1490  for (size_type k=0; k<permuteGIDs2.size(); k++)
1491  permuteGIDs2[k] = tgtMap2->getGlobalElement(permuteToLIDs2[k]);
1492 
1493  // Get remote GIDs
1494  ArrayView<const LO> remoteLIDs1 = this->getRemoteLIDs();
1495  Array<GO> remoteGIDs1(remoteLIDs1.size());
1496  for (size_type k=0; k<remoteLIDs1.size(); k++)
1497  remoteGIDs1[k] = this->getTargetMap()->getGlobalElement(remoteLIDs1[k]);
1498 
1499  ArrayView<const LO> remoteLIDs2 = rhs.getRemoteLIDs();
1500  Array<GO> remoteGIDs2(remoteLIDs2.size());
1501  for (size_type k=0; k<remoteLIDs2.size(); k++)
1502  remoteGIDs2[k] = rhs.getTargetMap()->getGlobalElement(remoteLIDs2[k]);
1503 
1504  // Get remote PIDs
1505  Array<int> remotePIDs1;
1506  Tpetra::Import_Util::getRemotePIDs(*this, remotePIDs1);
1507 
1508  Array<int> remotePIDs2;
1509  Tpetra::Import_Util::getRemotePIDs(rhs, remotePIDs2);
1510 
1511  // Get the union of the target GIDs
1512  Array<GO> unionTgtGIDs;
1513  Array<std::pair<int,GO>> remotePGIDs;
1514  size_type numSameIDsUnion, numPermuteIDsUnion, numRemoteIDsUnion;
1515 
1516  findUnionTargetGIDs(unionTgtGIDs, remotePGIDs,
1517  numSameIDsUnion, numPermuteIDsUnion, numRemoteIDsUnion,
1518  sameGIDs1, sameGIDs2, permuteGIDs1, permuteGIDs2,
1519  remoteGIDs1, remoteGIDs2, remotePIDs1, remotePIDs2);
1520 
1521  // Extract GIDs and compute LIDS, PIDs for the remotes in the union
1522  Array<LO> remoteLIDsUnion(numRemoteIDsUnion);
1523  Array<GO> remoteGIDsUnion(numRemoteIDsUnion);
1524  Array<int> remotePIDsUnion(numRemoteIDsUnion);
1525  const size_type unionRemoteIDsStart = numSameIDsUnion + numPermuteIDsUnion;
1526  for (size_type k = 0; k < numRemoteIDsUnion; ++k) {
1527  remoteLIDsUnion[k] = unionRemoteIDsStart + k;
1528  remotePIDsUnion[k] = remotePGIDs[k].first;
1529  remoteGIDsUnion[k] = remotePGIDs[k].second;
1530  }
1531 
1532  // Compute the permute-to LIDs (in the union target Map).
1533  // Convert the permute GIDs to permute-from LIDs in the source Map.
1534  Array<LO> permuteToLIDsUnion(numPermuteIDsUnion);
1535  Array<LO> permuteFromLIDsUnion(numPermuteIDsUnion);
1536  for (size_type k = 0; k < numPermuteIDsUnion; ++k) {
1537  size_type idx = numSameIDsUnion + k;
1538  permuteToLIDsUnion[k] = static_cast<LO>(idx);
1539  permuteFromLIDsUnion[k] = srcMap->getLocalElement(unionTgtGIDs[idx]);
1540  }
1541 
1542 #ifdef HAVE_TPETRA_MMM_TIMINGS
1543  MM.disableTimer(label);
1544  label = "Tpetra::Import::setUnion : Construct Target Map";
1545  TimeMonitor MM2(*TimeMonitor::getNewTimer(label));
1546 #endif
1547 
1548  // Create the union target Map.
1549  const GST INVALID = Teuchos::OrdinalTraits<GST>::invalid ();
1550  const GO indexBaseUnion = std::min(tgtMap1->getIndexBase(), tgtMap2->getIndexBase());
1551  RCP<const map_type> unionTgtMap =
1552  rcp(new map_type(INVALID, unionTgtGIDs(), indexBaseUnion, comm));
1553 
1554 #ifdef HAVE_TPETRA_MMM_TIMINGS
1555  MM2.disableTimer(label);
1556  label = "Tpetra::Import::setUnion : Export GIDs";
1557  TimeMonitor MM3(*TimeMonitor::getNewTimer(label));
1558 #endif
1559 
1560  // Thus far, we have computed the following in the union Import:
1561  // - numSameIDs
1562  // - numPermuteIDs and permuteFromLIDs
1563  // - numRemoteIDs, remoteGIDs, remoteLIDs, and remotePIDs
1564  //
1565  // Now it's time to compute the export IDs and initialize the
1566  // Distributor.
1567 
1568  Array<GO> exportGIDsUnion;
1569  Array<LO> exportLIDsUnion;
1570  Array<int> exportPIDsUnion;
1571  Distributor distributor (comm, this->TransferData_->out_);
1572 
1573 #ifdef TPETRA_IMPORT_SETUNION_USE_CREATE_FROM_SENDS
1574  // Compute the export IDs without communication, by merging the
1575  // lists of (export LID, export PID) pairs from the two input
1576  // Import objects. The export LIDs in both input Import objects
1577  // are LIDs in the source Map. Then, use the export PIDs to
1578  // initialize the Distributor via createFromSends.
1579 
1580  // const size_type numExportIDs1 = this->getNumExportIDs ();
1581  ArrayView<const LO> exportLIDs1 = this->getExportLIDs ();
1582  ArrayView<const LO> exportPIDs1 = this->getExportPIDs ();
1583 
1584  // const size_type numExportIDs2 = rhs.getNumExportIDs ();
1585  ArrayView<const LO> exportLIDs2 = rhs.getExportLIDs ();
1586  ArrayView<const LO> exportPIDs2 = rhs.getExportPIDs ();
1587 
1588  // We have to keep the export LIDs in PID-sorted order, then merge
1589  // them. So, first key-value merge (LID,PID) pairs, treating PIDs
1590  // as values, merging values by replacement. Then, sort the
1591  // (LID,PID) pairs again by PID.
1592 
1593  // Sort (LID,PID) pairs by LID for the later merge, and make
1594  // each sequence unique by LID.
1595  Array<LO> exportLIDs1Copy (exportLIDs1.begin (), exportLIDs1.end ());
1596  Array<int> exportPIDs1Copy (exportLIDs1.begin (), exportLIDs1.end ());
1597  sort2 (exportLIDs1Copy.begin (), exportLIDs1Copy.end (),
1598  exportPIDs1Copy.begin ());
1599  typename ArrayView<LO>::iterator exportLIDs1_end = exportLIDs1Copy.end ();
1600  typename ArrayView<LO>::iterator exportPIDs1_end = exportPIDs1Copy.end ();
1601  merge2 (exportLIDs1_end, exportPIDs1_end,
1602  exportLIDs1Copy.begin (), exportLIDs1_end,
1603  exportPIDs1Copy.begin (), exportPIDs1_end,
1604  project1st<LO, LO> ());
1605 
1606  Array<LO> exportLIDs2Copy (exportLIDs2.begin (), exportLIDs2.end ());
1607  Array<int> exportPIDs2Copy (exportLIDs2.begin (), exportLIDs2.end ());
1608  sort2 (exportLIDs2Copy.begin (), exportLIDs2Copy.end (),
1609  exportPIDs2Copy.begin ());
1610  typename ArrayView<LO>::iterator exportLIDs2_end = exportLIDs2Copy.end ();
1611  typename ArrayView<LO>::iterator exportPIDs2_end = exportPIDs2Copy.end ();
1612  merge2 (exportLIDs2_end, exportPIDs2_end,
1613  exportLIDs2Copy.begin (), exportLIDs2_end,
1614  exportPIDs2Copy.begin (), exportPIDs2_end,
1615  project1st<LO, LO> ());
1616 
1617  // Merge export (LID,PID) pairs. In this merge operation, the
1618  // LIDs are the "keys" and the PIDs their "values." We combine
1619  // the "values" (PIDs) in the pairs by replacement, rather than
1620  // by adding them together.
1621  keyValueMerge (exportLIDs1Copy.begin (), exportLIDs1Copy.end (),
1622  exportPIDs1Copy.begin (), exportPIDs1Copy.end (),
1623  exportLIDs2Copy.begin (), exportLIDs2Copy.end (),
1624  exportPIDs2Copy.begin (), exportPIDs2Copy.end (),
1625  std::back_inserter (exportLIDsUnion),
1626  std::back_inserter (exportPIDsUnion),
1628 
1629  // Resort the merged (LID,PID) pairs by PID.
1630  sort2 (exportPIDsUnion.begin (), exportPIDsUnion.end (),
1631  exportLIDsUnion.begin ());
1632 
1633  // Initialize the Distributor. Using createFromSends instead of
1634  // createFromRecvs avoids the initialization and use of a
1635  // temporary Distributor object.
1636  (void) distributor.createFromSends (exportPIDsUnion ().getConst ());
1637 #else // NOT TPETRA_IMPORT_SETUNION_USE_CREATE_FROM_SENDS
1638 
1639  // Call the Distributor's createFromRecvs() method to turn the
1640  // remote GIDs and their owning processes into a send-and-receive
1641  // communication plan. remoteGIDsUnion and remotePIDsUnion are
1642  // input; exportGIDsUnion and exportPIDsUnion are output arrays
1643  // which are allocated by createFromRecvs().
1644  distributor.createFromRecvs (remoteGIDsUnion().getConst(),
1645  remotePIDsUnion().getConst(),
1646  exportGIDsUnion, exportPIDsUnion);
1647 
1648  // Find the (source Map) LIDs corresponding to the export GIDs.
1649  const size_type numExportIDsUnion = exportGIDsUnion.size ();
1650  exportLIDsUnion.resize (numExportIDsUnion);
1651  for (size_type k = 0; k < numExportIDsUnion; ++k) {
1652  exportLIDsUnion[k] = srcMap->getLocalElement (exportGIDsUnion[k]);
1653  }
1654 #endif // TPETRA_IMPORT_SETUNION_USE_CREATE_FROM_SENDS
1655 
1656  // Create and return the union Import. This uses the "expert" constructor
1657 #ifdef HAVE_TPETRA_MMM_TIMINGS
1658  MM3.disableTimer(label);
1659  label = "Tpetra::Import::setUnion : Construct Import";
1660  TimeMonitor MM4(*TimeMonitor::getNewTimer(label));
1661 #endif
1662  RCP<const import_type> unionImport =
1663  rcp (new import_type (srcMap, unionTgtMap,
1664  as<size_t> (numSameIDsUnion),
1665  permuteToLIDsUnion, permuteFromLIDsUnion,
1666  remoteLIDsUnion, exportLIDsUnion,
1667  exportPIDsUnion, distributor,
1668  this->TransferData_->out_));
1669  return unionImport;
1670  }
1671 
1672  template <class LocalOrdinal, class GlobalOrdinal, class Node>
1673  Teuchos::RCP<const Import<LocalOrdinal, GlobalOrdinal, Node> >
1675  setUnion () const
1676  {
1677  using Teuchos::Array;
1678  using Teuchos::ArrayView;
1679  using Teuchos::as;
1680  using Teuchos::Comm;
1681  using Teuchos::RCP;
1682  using Teuchos::rcp;
1683  using Teuchos::outArg;
1684  using Teuchos::REDUCE_MIN;
1685  using Teuchos::reduceAll;
1686  typedef LocalOrdinal LO;
1687  typedef GlobalOrdinal GO;
1688  Teuchos::RCP<const Import<LocalOrdinal, GlobalOrdinal, Node> > unionImport;
1689  RCP<const map_type> srcMap = this->getSourceMap ();
1690  RCP<const map_type> tgtMap = this->getTargetMap ();
1691  RCP<const Comm<int> > comm = srcMap->getComm ();
1692 
1693  ArrayView<const GO> srcGIDs = srcMap->getNodeElementList ();
1694  ArrayView<const GO> tgtGIDs = tgtMap->getNodeElementList ();
1695 
1696  // All elements in srcMap will be in the "new" target map, so...
1697  size_t numSameIDsNew = srcMap->getNodeNumElements ();
1698  size_t numRemoteIDsNew = this->getNumRemoteIDs ();
1699  Array<LO> permuteToLIDsNew, permuteFromLIDsNew; // empty on purpose
1700 
1701  // Grab some old data
1702  ArrayView<const LO> remoteLIDsOld = this->getRemoteLIDs ();
1703  ArrayView<const LO> exportLIDsOld = this->getExportLIDs ();
1704 
1705  // Build up the new map (same part)
1706  Array<GO> GIDs(numSameIDsNew + numRemoteIDsNew);
1707  for(size_t i=0; i<numSameIDsNew; i++)
1708  GIDs[i] = srcGIDs[i];
1709 
1710  // Build up the new map (remote part) and remotes list
1711  Array<LO> remoteLIDsNew(numRemoteIDsNew);
1712  for(size_t i=0; i<numRemoteIDsNew; i++) {
1713  GIDs[numSameIDsNew + i] = tgtGIDs[remoteLIDsOld[i]];
1714  remoteLIDsNew[i] = numSameIDsNew+i;
1715  }
1716 
1717  // Build the new target map
1718  GO GO_INVALID = Teuchos::OrdinalTraits<GO>::invalid();
1719  RCP<const map_type> targetMapNew =
1720  rcp (new map_type (GO_INVALID, GIDs, tgtMap->getIndexBase (),
1721  tgtMap->getComm ()));
1722 
1723  // Exports are trivial (since the sourcemap doesn't change)
1724  Array<int> exportPIDsnew (this->getExportPIDs ());
1725  Array<LO> exportLIDsnew (this->getExportLIDs ());
1726 
1727  // Copy the Distributor (due to how the Import constructor works)
1728  Distributor D (this->getDistributor ());
1729 
1730  // Build the importer using the "expert" constructor
1731  unionImport = rcp(new Import<LocalOrdinal, GlobalOrdinal, Node>(srcMap,
1732  targetMapNew,
1733  numSameIDsNew,
1734  permuteToLIDsNew,
1735  permuteFromLIDsNew,
1736  remoteLIDsNew,
1737  exportLIDsnew,
1738  exportPIDsnew,D));
1739 
1740  return unionImport;
1741  }
1742 
1743 
1744 
1745 
1746  template <class LocalOrdinal, class GlobalOrdinal, class Node>
1747  Teuchos::RCP<const Import<LocalOrdinal, GlobalOrdinal, Node> >
1749  createRemoteOnlyImport (const Teuchos::RCP<const map_type>& remoteTarget) const
1750  {
1751  using Teuchos::rcp;
1752  using import_type = Import<LocalOrdinal,GlobalOrdinal,Node>;
1753  using LO = LocalOrdinal;
1754 
1755  const size_t NumRemotes = this->getNumRemoteIDs ();
1756  TEUCHOS_TEST_FOR_EXCEPTION(
1757  NumRemotes != remoteTarget->getNodeNumElements (),
1758  std::runtime_error, "Tpetra::createRemoteOnlyImport: "
1759  "remoteTarget map ID count doesn't match.");
1760 
1761  // Compute the new Remote LIDs
1762  Teuchos::ArrayView<const LO> oldRemoteLIDs = this->getRemoteLIDs ();
1763  Teuchos::Array<LO> newRemoteLIDs (NumRemotes);
1764  const map_type& tgtMap = * (this->getTargetMap ());
1765  for (size_t i = 0; i < NumRemotes; ++i) {
1766  newRemoteLIDs[i] = remoteTarget->getLocalElement (tgtMap.getGlobalElement (oldRemoteLIDs[i]));
1767  // Now we make sure these guys are in sorted order (AztecOO-ML ordering)
1768  TEUCHOS_TEST_FOR_EXCEPTION(
1769  i > 0 && newRemoteLIDs[i] < newRemoteLIDs[i-1],
1770  std::runtime_error, "Tpetra::createRemoteOnlyImport: "
1771  "this and remoteTarget order don't match.");
1772  }
1773 
1774  // Copy ExportPIDs and such
1775  // NOTE: Be careful: The "Expert" Import constructor we use does a "swap"
1776  // for most of the LID/PID lists and the Distributor, meaning it
1777  // ruins the existing object if we pass things in directly. Hence
1778  // we copy them first.
1779  Teuchos::Array<int> newExportPIDs (this->getExportPIDs ());
1780  Teuchos::Array<LO> newExportLIDs (this->getExportLIDs ());
1781  Teuchos::Array<LO> dummy;
1782  Distributor newDistor (this->getDistributor ());
1783 
1784  return rcp (new import_type (this->getSourceMap (), remoteTarget,
1785  static_cast<size_t> (0), dummy, dummy,
1786  newRemoteLIDs, newExportLIDs,
1787  newExportPIDs, newDistor));
1788  }
1789 
1790 } // namespace Tpetra
1791 
1792 #define TPETRA_IMPORT_CLASS_INSTANT(LO, GO, NODE) \
1793  template class Import< LO , GO , NODE >;
1794 
1795 // Explicit instantiation macro.
1796 // Only invoke this when in the Tpetra namespace.
1797 // Most users do not need to use this.
1798 //
1799 // LO: The local ordinal type.
1800 // GO: The global ordinal type.
1801 // NODE: The Kokkos Node type.
1802 #define TPETRA_IMPORT_INSTANT(LO, GO, NODE) \
1803  TPETRA_IMPORT_CLASS_INSTANT(LO, GO, NODE)
1804 
1805 #endif // TPETRA_IMPORT_DEF_HPP
bool congruent(const Teuchos::Comm< int > &comm1, const Teuchos::Comm< int > &comm2)
Whether the two communicators are congruent.
Definition: Tpetra_Util.cpp:65
Communication plan for data redistribution from a uniquely-owned to a (possibly) multiply-owned distr...
void merge2(IT1 &indResultOut, IT2 &valResultOut, IT1 indBeg, IT1 indEnd, IT2 valBeg, IT2)
Merge values in place, additively, with the same index.
Teuchos::FancyOStream & verboseOutputStream() const
Valid (nonnull) output stream for verbose output.
Teuchos::RCP< const Import< LocalOrdinal, GlobalOrdinal, Node > > createRemoteOnlyImport(const Teuchos::RCP< const map_type > &remoteTarget) const
Returns an importer that contains only the remote entries of this.
void sort3(const IT1 &first1, const IT1 &last1, const IT2 &first2, const IT3 &first3)
Sort the first array, and apply the same permutation to the second and third arrays.
Declaration of Tpetra::Details::Profiling, a scope guard for Kokkos Profiling.
LookupStatus
Return status of Map remote index lookup (getRemoteIndexList()).
Teuchos::ArrayView< const int > getExportPIDs() const
List of processes to which entries will be sent.
Teuchos::ArrayView< const LocalOrdinal > getPermuteToLIDs() const
List of local IDs in the target Map that are permuted.
virtual void describe(Teuchos::FancyOStream &out, const Teuchos::EVerbosityLevel verbLevel=Teuchos::Describable::verbLevel_default) const
Describe this object in a human-readable way to the given output stream.
Teuchos::RCP< const map_type > getTargetMap() const
The target Map used to construct this Export or Import.
size_t getNumSameIDs() const
Number of initial identical IDs.
size_t getNumRemoteIDs() const
Number of entries not on the calling process.
size_t createFromSends(const Teuchos::ArrayView< const int > &exportProcIDs)
Set up Distributor using list of process ranks to which this process will send.
Teuchos::RCP< const Import< LocalOrdinal, GlobalOrdinal, Node > > setUnion() const
Return the union of this Import this-&gt;getSourceMap()
size_t global_size_t
Global size_t object.
Import(const Teuchos::RCP< const map_type > &source, const Teuchos::RCP< const map_type > &target)
Construct an Import from the source and target Maps.
Teuchos::ArrayView< const LocalOrdinal > getRemoteLIDs() const
List of entries in the target Map to receive from other processes.
void keyValueMerge(KeyInputIterType keyBeg1, KeyInputIterType keyEnd1, ValueInputIterType valBeg1, ValueInputIterType valEnd1, KeyInputIterType keyBeg2, KeyInputIterType keyEnd2, ValueInputIterType valBeg2, ValueInputIterType valEnd2, KeyOutputIterType keyOut, ValueOutputIterType valOut, BinaryFunction f)
Merge two sorted (by keys) sequences of unique (key,value) pairs by combining pairs with equal keys...
void createFromSendsAndRecvs(const Teuchos::ArrayView< const int > &exportProcIDs, const Teuchos::ArrayView< const int > &remoteProcIDs)
Set up Distributor using list of process ranks to which to send, and list of process ranks from which...
auto view_alloc_no_init(const std::string &label) ->
Use in place of the string label as the first argument of Kokkos::View&#39;s constructor, in case you want to allocate without initializing.
Communication plan for data redistribution from a (possibly) multiply-owned to a uniquely-owned distr...
#define TPETRA_ABUSE_WARNING(throw_exception_test, Exception, msg)
Handle an abuse warning, according to HAVE_TPETRA_THROW_ABUSE_WARNINGS and HAVE_TPETRA_PRINT_ABUSE_WA...
Implementation detail of Import and Export.
Sets up and executes a communication plan for a Tpetra DistObject.
GlobalOrdinal getGlobalElement(LocalOrdinal localIndex) const
The global index corresponding to the given local index.
Teuchos::RCP< ImportExportData< LocalOrdinal, GlobalOrdinal, Node > > TransferData_
All the data needed for executing the Export communication plan.
Teuchos::RCP< const map_type > getSourceMap() const
The source Map used to construct this Export or Import.
void findUnionTargetGIDs(Teuchos::Array< GlobalOrdinal > &unionTgtGIDs, Teuchos::Array< std::pair< int, GlobalOrdinal >> &remotePGIDs, typename Teuchos::Array< GlobalOrdinal >::size_type &numSameGIDs, typename Teuchos::Array< GlobalOrdinal >::size_type &numPermuteGIDs, typename Teuchos::Array< GlobalOrdinal >::size_type &numRemoteGIDs, const Teuchos::ArrayView< const GlobalOrdinal > &sameGIDs1, const Teuchos::ArrayView< const GlobalOrdinal > &sameGIDs2, Teuchos::Array< GlobalOrdinal > &permuteGIDs1, Teuchos::Array< GlobalOrdinal > &permuteGIDs2, Teuchos::Array< GlobalOrdinal > &remoteGIDs1, Teuchos::Array< GlobalOrdinal > &remoteGIDs2, Teuchos::Array< int > &remotePIDs1, Teuchos::Array< int > &remotePIDs2) const
Find the union of the target IDs from two Import objects.
Teuchos::ArrayView< const LocalOrdinal > getExportLIDs() const
List of entries in the source Map that will be sent to other processes.
void sort2(const IT1 &first1, const IT1 &last1, const IT2 &first2)
Sort the first array, and apply the resulting permutation to the second array.
A parallel distribution of indices over processes.
Internal functions and macros designed for use with Tpetra::Import and Tpetra::Export objects...
Stand-alone utility functions and macros.
void makeDualViewFromOwningHostView(Kokkos::DualView< ElementType *, DeviceType > &dv, const typename Kokkos::DualView< ElementType *, DeviceType >::t_host &hostView)
Initialize dv such that its host View is hostView.
bool verbose() const
Whether to print verbose debugging output.
virtual void print(std::ostream &os) const
Print the Import&#39;s data to the given output stream.
void createFromRecvs(const Teuchos::ArrayView< const Ordinal > &remoteIDs, const Teuchos::ArrayView< const int > &remoteProcIDs, Teuchos::Array< Ordinal > &exportIDs, Teuchos::Array< int > &exportProcIDs)
Set up Distributor using list of process ranks from which to receive.
Binary function that returns its first argument.
Declaration of Tpetra::Details::Behavior, a class that describes Tpetra&#39;s behavior.