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