Tpetra Matrix/Vector Services Version of the Day
Tpetra_Import_def.hpp
00001 // @HEADER
00002 // ***********************************************************************
00003 //
00004 //          Tpetra: Templated Linear Algebra Services Package
00005 //                 Copyright (2008) Sandia Corporation
00006 //
00007 // Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
00008 // the U.S. Government retains certain rights in this software.
00009 //
00010 // Redistribution and use in source and binary forms, with or without
00011 // modification, are permitted provided that the following conditions are
00012 // met:
00013 //
00014 // 1. Redistributions of source code must retain the above copyright
00015 // notice, this list of conditions and the following disclaimer.
00016 //
00017 // 2. Redistributions in binary form must reproduce the above copyright
00018 // notice, this list of conditions and the following disclaimer in the
00019 // documentation and/or other materials provided with the distribution.
00020 //
00021 // 3. Neither the name of the Corporation nor the names of the
00022 // contributors may be used to endorse or promote products derived from
00023 // this software without specific prior written permission.
00024 //
00025 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
00026 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00027 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
00028 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
00029 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00030 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00031 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00032 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00033 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00034 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00035 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00036 //
00037 // Questions? Contact Michael A. Heroux (maherou@sandia.gov)
00038 //
00039 // ************************************************************************
00040 // @HEADER
00041 
00042 #ifndef TPETRA_IMPORT_DEF_HPP
00043 #define TPETRA_IMPORT_DEF_HPP
00044 
00045 #ifdef DOXYGEN_USE_ONLY
00046 #  include <Tpetra_Import_decl.hpp>
00047 #endif // DOXYGEN_USE_ONLY
00048 
00049 #include <Tpetra_Distributor.hpp>
00050 #include <Tpetra_Map.hpp>
00051 #include <Tpetra_ImportExportData.hpp>
00052 #include <Tpetra_Util.hpp>
00053 #include <Tpetra_Import_Util.hpp>
00054 #include <Tpetra_Export.hpp>
00055 #include <Teuchos_as.hpp>
00056 
00057 
00058 namespace {
00059   // Default value of Import's "Debug" parameter.
00060   const bool tpetraImportDebugDefault = false;
00061 } // namespace (anonymous)
00062 
00063 namespace Tpetra {
00064 
00065   template <class LocalOrdinal, class GlobalOrdinal, class Node>
00066   void
00067   Import<LocalOrdinal,GlobalOrdinal,Node>::
00068   setParameterList (const Teuchos::RCP<Teuchos::ParameterList>& plist)
00069   {
00070     bool debug = tpetraImportDebugDefault;
00071     if (! plist.is_null ()) {
00072       try {
00073         debug = plist->get<bool> ("Debug");
00074       } catch (Teuchos::Exceptions::InvalidParameter&) {}
00075     }
00076     debug_ = debug;
00077     ImportData_->distributor_.setParameterList (plist);
00078   }
00079 
00080   template <class LocalOrdinal, class GlobalOrdinal, class Node>
00081   void
00082   Import<LocalOrdinal,GlobalOrdinal,Node>::
00083   init (const Teuchos::RCP<const Map<LocalOrdinal,GlobalOrdinal,Node> >& source,
00084         const Teuchos::RCP<const Map<LocalOrdinal,GlobalOrdinal,Node> >& target,
00085         bool useRemotePIDs,
00086         Teuchos::Array<int> & remotePIDs,
00087         const Teuchos::RCP<Teuchos::ParameterList>& plist)
00088   {
00089     using Teuchos::null;
00090     using Teuchos::Ptr;
00091     using Teuchos::rcp;
00092     using std::endl;
00093     typedef ImportExportData<LocalOrdinal,GlobalOrdinal,Node> data_type;
00094 
00095     // Read "Debug" parameter from the input ParameterList.
00096     bool debug = tpetraImportDebugDefault;
00097     if (! plist.is_null ()) {
00098       try {
00099         debug = plist->get<bool> ("Debug");
00100       } catch (Teuchos::Exceptions::InvalidParameter&) {}
00101     }
00102     debug_ = debug;
00103 
00104     if (! out_.is_null ()) {
00105       out_->pushTab ();
00106     }
00107     if (debug_) {
00108       std::ostringstream os;
00109       const int myRank = source->getComm ()->getRank ();
00110       os << myRank << ": Import ctor" << endl;
00111       *out_ << os.str ();
00112     }
00113     ImportData_ = rcp (new data_type (source, target, out_, plist));
00114 
00115     Array<GlobalOrdinal> remoteGIDs;
00116     setupSamePermuteRemote (remoteGIDs);
00117     if (debug_) {
00118       std::ostringstream os;
00119       const int myRank = source->getComm ()->getRank ();
00120       os << myRank << ": Import ctor: "
00121          << "setupSamePermuteRemote done" << endl;
00122       *out_ << os.str ();
00123     }
00124     if (source->isDistributed ()) {
00125       setupExport (remoteGIDs,useRemotePIDs,remotePIDs);
00126     }
00127     if (debug_) {
00128       std::ostringstream os;
00129       const int myRank = source->getComm ()->getRank ();
00130       os << myRank << ": Import ctor: done" << endl;
00131       *out_ << os.str ();
00132     }
00133     if (! out_.is_null ()) {
00134       out_->popTab ();
00135     }
00136   }
00137 
00138   template <class LocalOrdinal, class GlobalOrdinal, class Node>
00139   Import<LocalOrdinal,GlobalOrdinal,Node>::
00140   Import (const RCP<const Map<LocalOrdinal,GlobalOrdinal,Node> >& source,
00141           const RCP<const Map<LocalOrdinal,GlobalOrdinal,Node> >& target) :
00142     out_ (Teuchos::getFancyOStream (Teuchos::rcpFromRef (std::cerr))),
00143     debug_ (tpetraImportDebugDefault)
00144   {
00145     Teuchos::Array<int> dummy;
00146     init (source, target, false, dummy, Teuchos::null);
00147   }
00148 
00149   template <class LocalOrdinal, class GlobalOrdinal, class Node>
00150   Import<LocalOrdinal,GlobalOrdinal,Node>::
00151   Import (const RCP<const Map<LocalOrdinal,GlobalOrdinal,Node> >& source,
00152           const RCP<const Map<LocalOrdinal,GlobalOrdinal,Node> >& target,
00153           const RCP<Teuchos::FancyOStream>& out) :
00154     out_ (out),
00155     debug_ (tpetraImportDebugDefault)
00156   {
00157     Teuchos::Array<int> dummy;
00158     init (source, target, false, dummy, Teuchos::null);
00159   }
00160 
00161   template <class LocalOrdinal, class GlobalOrdinal, class Node>
00162   Import<LocalOrdinal,GlobalOrdinal,Node>::
00163   Import (const Teuchos::RCP<const Map<LocalOrdinal,GlobalOrdinal,Node> >& source,
00164           const Teuchos::RCP<const Map<LocalOrdinal,GlobalOrdinal,Node> >& target,
00165           const Teuchos::RCP<Teuchos::ParameterList>& plist) :
00166     out_ (Teuchos::getFancyOStream (Teuchos::rcpFromRef (std::cerr))),
00167     debug_ (tpetraImportDebugDefault)
00168   {
00169     Teuchos::Array<int> dummy;
00170     init (source, target, false, dummy, plist);
00171   }
00172 
00173   template <class LocalOrdinal, class GlobalOrdinal, class Node>
00174   Import<LocalOrdinal,GlobalOrdinal,Node>::
00175   Import (const Teuchos::RCP<const Map<LocalOrdinal,GlobalOrdinal,Node> >& source,
00176           const Teuchos::RCP<const Map<LocalOrdinal,GlobalOrdinal,Node> >& target,
00177           const RCP<Teuchos::FancyOStream>& out,
00178           const Teuchos::RCP<Teuchos::ParameterList>& plist) :
00179     out_ (out),
00180     debug_ (tpetraImportDebugDefault)
00181   {
00182     Teuchos::Array<int> dummy;
00183     init (source, target, false, dummy, plist);
00184   }
00185 
00186   template <class LocalOrdinal, class GlobalOrdinal, class Node>
00187   Import<LocalOrdinal,GlobalOrdinal,Node>::
00188   Import (const Teuchos::RCP<const Map<LocalOrdinal,GlobalOrdinal,Node> >& source,
00189           const Teuchos::RCP<const Map<LocalOrdinal,GlobalOrdinal,Node> >& target,
00190           Teuchos::Array<int> & remotePIDs) :
00191     debug_ (tpetraImportDebugDefault)
00192   {
00193     init (source, target, true, remotePIDs, Teuchos::null);
00194   }
00195 
00196 
00197   template <class LocalOrdinal, class GlobalOrdinal, class Node>
00198   Import<LocalOrdinal,GlobalOrdinal,Node>::
00199   Import (const Import<LocalOrdinal,GlobalOrdinal,Node>& rhs)
00200     : ImportData_ (rhs.ImportData_)
00201     , out_ (rhs.out_)
00202     , debug_ (rhs.debug_)
00203   {}
00204 
00205   template <class LocalOrdinal, class GlobalOrdinal, class Node>
00206   Import<LocalOrdinal,GlobalOrdinal,Node>::
00207   Import (const Export<LocalOrdinal,GlobalOrdinal,Node>& exporter)
00208     : out_ (exporter.out_)
00209     , debug_ (exporter.debug_)
00210   {
00211     if (! exporter.ExportData_.is_null ()) {
00212       ImportData_ = exporter.ExportData_->reverseClone ();
00213     }
00214   }
00215 
00216   template <class LocalOrdinal, class GlobalOrdinal, class Node>
00217   Import<LocalOrdinal,GlobalOrdinal,Node>::
00218   Import (const Teuchos::RCP<const map_type>& source,
00219           const Teuchos::RCP<const map_type>& target,
00220           const size_t numSameIDs,
00221           Teuchos::Array<LocalOrdinal>& permuteToLIDs,
00222           Teuchos::Array<LocalOrdinal>& permuteFromLIDs,
00223           Teuchos::Array<LocalOrdinal>& remoteLIDs,
00224           Teuchos::Array<LocalOrdinal>& exportLIDs,
00225           Teuchos::Array<int>& exportPIDs,
00226           Distributor& distributor,
00227           const Teuchos::RCP<Teuchos::FancyOStream>& out,
00228           const Teuchos::RCP<Teuchos::ParameterList>& plist) :
00229     out_ (out.is_null () ? Teuchos::getFancyOStream (Teuchos::rcpFromRef (std::cerr)) : out),
00230     debug_ (tpetraImportDebugDefault)
00231   {
00232     using Teuchos::null;
00233     using Teuchos::Ptr;
00234     using Teuchos::rcp;
00235     using std::cerr;
00236     using std::endl;
00237     typedef ImportExportData<LocalOrdinal,GlobalOrdinal,Node> data_type;
00238 
00239     // Read "Debug" parameter from the input ParameterList.
00240     bool debug = tpetraImportDebugDefault;
00241     if (! plist.is_null ()) {
00242       try {
00243         debug = plist->get<bool> ("Debug");
00244       } catch (Teuchos::Exceptions::InvalidParameter&) {}
00245     }
00246     debug_ = debug;
00247 
00248     if (! out_.is_null ()) {
00249       out_->pushTab ();
00250     }
00251     if (debug_ && ! out_.is_null ()) {
00252       std::ostringstream os;
00253       const int myRank = source->getComm ()->getRank ();
00254       os << myRank << ": Import expert ctor" << endl;
00255       *out_ << os.str ();
00256     }
00257     ImportData_ = rcp (new data_type (source, target, out_, plist));
00258 
00259     ImportData_->numSameIDs_ = numSameIDs;
00260     ImportData_->permuteToLIDs_.swap (permuteToLIDs);
00261     ImportData_->permuteFromLIDs_.swap (permuteFromLIDs);
00262     ImportData_->remoteLIDs_.swap (remoteLIDs);
00263     ImportData_->distributor_.swap (distributor);
00264     ImportData_->exportLIDs_.swap (exportLIDs);
00265     ImportData_->exportPIDs_.swap (exportPIDs);
00266   }
00267 
00268   template <class LocalOrdinal, class GlobalOrdinal, class Node>
00269   Import<LocalOrdinal,GlobalOrdinal,Node>::~Import()
00270   {}
00271 
00272   template <class LocalOrdinal, class GlobalOrdinal, class Node>
00273   size_t Import<LocalOrdinal,GlobalOrdinal,Node>::getNumSameIDs() const {
00274     return ImportData_->numSameIDs_;
00275   }
00276 
00277   template <class LocalOrdinal, class GlobalOrdinal, class Node>
00278   size_t Import<LocalOrdinal,GlobalOrdinal,Node>::getNumPermuteIDs() const {
00279     return ImportData_->permuteFromLIDs_.size();
00280   }
00281 
00282   template <class LocalOrdinal, class GlobalOrdinal, class Node>
00283   ArrayView<const LocalOrdinal>
00284   Import<LocalOrdinal,GlobalOrdinal,Node>::getPermuteFromLIDs() const {
00285     return ImportData_->permuteFromLIDs_();
00286   }
00287 
00288   template <class LocalOrdinal, class GlobalOrdinal, class Node>
00289   ArrayView<const LocalOrdinal>
00290   Import<LocalOrdinal,GlobalOrdinal,Node>::getPermuteToLIDs() const {
00291     return ImportData_->permuteToLIDs_();
00292   }
00293 
00294   template <class LocalOrdinal, class GlobalOrdinal, class Node>
00295   size_t Import<LocalOrdinal,GlobalOrdinal,Node>::getNumRemoteIDs() const {
00296     return ImportData_->remoteLIDs_.size();
00297   }
00298 
00299   template <class LocalOrdinal, class GlobalOrdinal, class Node>
00300   ArrayView<const LocalOrdinal>
00301   Import<LocalOrdinal,GlobalOrdinal,Node>::getRemoteLIDs() const {
00302     return ImportData_->remoteLIDs_();
00303   }
00304 
00305   template <class LocalOrdinal, class GlobalOrdinal, class Node>
00306   size_t Import<LocalOrdinal,GlobalOrdinal,Node>::getNumExportIDs() const {
00307     return ImportData_->exportLIDs_.size();
00308   }
00309 
00310   template <class LocalOrdinal, class GlobalOrdinal, class Node>
00311   ArrayView<const LocalOrdinal>
00312   Import<LocalOrdinal,GlobalOrdinal,Node>::getExportLIDs() const {
00313     return ImportData_->exportLIDs_();
00314   }
00315 
00316   template <class LocalOrdinal, class GlobalOrdinal, class Node>
00317   ArrayView<const int>
00318   Import<LocalOrdinal,GlobalOrdinal,Node>::getExportPIDs() const {
00319     return ImportData_->exportPIDs_();
00320   }
00321 
00322   template <class LocalOrdinal, class GlobalOrdinal, class Node>
00323   Teuchos::RCP<const Map<LocalOrdinal,GlobalOrdinal,Node> >
00324   Import<LocalOrdinal,GlobalOrdinal,Node>::getSourceMap() const {
00325     return ImportData_->source_;
00326   }
00327 
00328   template <class LocalOrdinal, class GlobalOrdinal, class Node>
00329   Teuchos::RCP<const Map<LocalOrdinal,GlobalOrdinal,Node> >
00330   Import<LocalOrdinal,GlobalOrdinal,Node>::getTargetMap() const {
00331     return ImportData_->target_;
00332   }
00333 
00334   template <class LocalOrdinal, class GlobalOrdinal, class Node>
00335   Distributor &
00336   Import<LocalOrdinal,GlobalOrdinal,Node>::getDistributor() const {
00337     return ImportData_->distributor_;
00338   }
00339 
00340   template <class LocalOrdinal, class GlobalOrdinal, class Node>
00341   Import<LocalOrdinal,GlobalOrdinal,Node>&
00342   Import<LocalOrdinal,GlobalOrdinal,Node>::
00343   operator= (const Import<LocalOrdinal,GlobalOrdinal,Node>& rhs) {
00344     if (&rhs != this) {
00345       ImportData_ = rhs.ImportData_;
00346     }
00347     return *this;
00348   }
00349 
00350   template <class LocalOrdinal, class GlobalOrdinal, class Node>
00351   void Import<LocalOrdinal,GlobalOrdinal,Node>::
00352   print (std::ostream& os) const
00353   {
00354     using Teuchos::Comm;
00355     using Teuchos::getFancyOStream;
00356     using Teuchos::RCP;
00357     using Teuchos::rcpFromRef;
00358     using Teuchos::toString;
00359     using std::endl;
00360 
00361     RCP<const Comm<int> > comm = getSourceMap ()->getComm ();
00362     const int myImageID = comm->getRank ();
00363     const int numImages = comm->getSize ();
00364     for (int imageCtr = 0; imageCtr < numImages; ++imageCtr) {
00365       if (myImageID == imageCtr) {
00366         os << endl;
00367         if (myImageID == 0) { // I'm the root node (only output this info once)
00368           os << "Import Data Members:" << endl;
00369         }
00370         os << "Image ID       : " << myImageID << endl;
00371 
00372         os << "permuteFromLIDs: " << toString (getPermuteFromLIDs ()) << endl;
00373         os << "permuteToLIDs  : " << toString (getPermuteToLIDs ()) << endl;
00374         os << "remoteLIDs     : " << toString (getRemoteLIDs ()) << endl;
00375         os << "exportLIDs     : " << toString (getExportLIDs ()) << endl;
00376         os << "exportPIDs     : " << toString (getExportPIDs ()) << endl;
00377 
00378         os << "numSameIDs     : " << getNumSameIDs () << endl;
00379         os << "numPermuteIDs  : " << getNumPermuteIDs () << endl;
00380         os << "numRemoteIDs   : " << getNumRemoteIDs () << endl;
00381         os << "numExportIDs   : " << getNumExportIDs () << endl;
00382       }
00383       // A few global barriers give output a chance to complete.
00384       comm->barrier();
00385       comm->barrier();
00386       comm->barrier();
00387     }
00388 
00389     const bool printMaps = false;
00390     if (printMaps) {
00391       if (myImageID == 0) {
00392         os << endl << endl << "Source Map:" << endl << std::flush;
00393       }
00394       comm->barrier();
00395       os << *getSourceMap();
00396       comm->barrier();
00397 
00398       if (myImageID == 0) {
00399         os << endl << endl << "Target Map:" << endl << std::flush;
00400       }
00401       comm->barrier();
00402       os << *getTargetMap();
00403       comm->barrier();
00404     }
00405 
00406     // It's also helpful for debugging to print the Distributor
00407     // object.  Epetra_Import::Print() does this, so we can do a
00408     // side-by-side comparison.
00409     if (myImageID == 0) {
00410       os << endl << endl << "Distributor:" << endl << std::flush;
00411     }
00412     comm->barrier();
00413     getDistributor().describe (*(getFancyOStream (rcpFromRef (os))),
00414                                Teuchos::VERB_EXTREME);
00415   }
00416 
00417 
00418   template <class LocalOrdinal, class GlobalOrdinal, class Node>
00419   void
00420   Import<LocalOrdinal,GlobalOrdinal,Node>::
00421   setupSamePermuteRemote (Teuchos::Array<GlobalOrdinal>& remoteGIDs)
00422   {
00423     using Teuchos::arcp;
00424     using Teuchos::Array;
00425     using Teuchos::ArrayRCP;
00426     using Teuchos::ArrayView;
00427     using Teuchos::as;
00428     using Teuchos::null;
00429     typedef LocalOrdinal LO;
00430     typedef GlobalOrdinal GO;
00431     typedef typename ArrayView<const GO>::size_type size_type;
00432     const Map<LO,GO,Node>& source = * (getSourceMap ());
00433     const Map<LO,GO,Node>& target = * (getTargetMap ());
00434     ArrayView<const GO> sourceGIDs = source.getNodeElementList ();
00435     ArrayView<const GO> targetGIDs = target.getNodeElementList ();
00436 
00437 #ifdef HAVE_TPETRA_DEBUG
00438     ArrayView<const GO> rawSrcGids = sourceGIDs;
00439     ArrayView<const GO> rawTgtGids = targetGIDs;
00440 #else
00441     const GO* const rawSrcGids = sourceGIDs.getRawPtr ();
00442     const GO* const rawTgtGids = targetGIDs.getRawPtr ();
00443 #endif // HAVE_TPETRA_DEBUG
00444     const size_type numSrcGids = sourceGIDs.size ();
00445     const size_type numTgtGids = targetGIDs.size ();
00446     const size_type numGids = std::min (numSrcGids, numTgtGids);
00447 
00448     // Compute numSameIDs_: the number of initial GIDs that are the
00449     // same (and occur in the same order) in both Maps.  The point of
00450     // numSameIDs_ is for the common case of an Import where all the
00451     // overlapping GIDs are at the end of the target Map, but
00452     // otherwise the source and target Maps are the same.  This allows
00453     // a fast contiguous copy for the initial "same IDs."
00454     size_type numSameGids = 0;
00455     for ( ; numSameGids < numGids && rawSrcGids[numSameGids] == rawTgtGids[numSameGids]; ++numSameGids)
00456       {} // third clause of 'for' does everything
00457     ImportData_->numSameIDs_ = numSameGids;
00458 
00459     // Compute permuteToLIDs_, permuteFromLIDs_, remoteGIDs, and
00460     // remoteLIDs_.  The first two arrays are IDs to be permuted, and
00461     // the latter two arrays are IDs to be received ("imported"),
00462     // called "remote" IDs.
00463     //
00464     // IDs to permute are in both the source and target Maps, which
00465     // means we don't have to send or receive them, but we do have to
00466     // rearrange (permute) them in general.  IDs to receive are in the
00467     // target Map, but not the source Map.
00468 
00469     Array<LO>& permuteToLIDs = ImportData_->permuteToLIDs_;
00470     Array<LO>& permuteFromLIDs = ImportData_->permuteFromLIDs_;
00471     Array<LO>& remoteLIDs = ImportData_->remoteLIDs_;
00472     const LO LINVALID = Teuchos::OrdinalTraits<LO>::invalid ();
00473     const LO numTgtLids = as<LO> (numTgtGids);
00474     // Iterate over the target Map's LIDs, since we only need to do
00475     // GID -> LID lookups for the source Map.
00476     for (LO tgtLid = numSameGids; tgtLid < numTgtLids; ++tgtLid) {
00477       const GO curTargetGid = rawTgtGids[tgtLid];
00478       // getLocalElement() returns LINVALID if the GID isn't in the source Map.
00479       // This saves us a lookup (which isNodeGlobalElement() would do).
00480       const LO srcLid = source.getLocalElement (curTargetGid);
00481       if (srcLid != LINVALID) { // if source.isNodeGlobalElement (curTargetGid)
00482         permuteToLIDs.push_back (tgtLid);
00483         permuteFromLIDs.push_back (srcLid);
00484       } else {
00485         remoteGIDs.push_back (curTargetGid);
00486         remoteLIDs.push_back (tgtLid);
00487       }
00488     }
00489 
00490     TPETRA_ABUSE_WARNING(
00491       getNumRemoteIDs() > 0 && ! source.isDistributed(),
00492       std::runtime_error,
00493       "::setupSamePermuteRemote(): Target has remote LIDs but Source is not "
00494       "distributed globally." << std::endl
00495       << "Importing to a submap of the target map.");
00496   }
00497 
00498 
00499   template <class LocalOrdinal, class GlobalOrdinal, class Node>
00500   void Import<LocalOrdinal,GlobalOrdinal,Node>::
00501   setupExport (Teuchos::Array<GlobalOrdinal>& remoteGIDs,
00502                bool useRemotePIDs,
00503                Teuchos::Array<int>& userRemotePIDs)
00504   {
00505     using Teuchos::arcp;
00506     using Teuchos::Array;
00507     using Teuchos::ArrayRCP;
00508     using Teuchos::ArrayView;
00509     using Teuchos::null;
00510     using std::endl;
00511     typedef LocalOrdinal LO;
00512     typedef GlobalOrdinal GO;
00513     typedef typename Array<int>::difference_type size_type;
00514 
00515     TEUCHOS_TEST_FOR_EXCEPTION(
00516       getSourceMap ().is_null (), std::logic_error, "Tpetra::Import::"
00517       "setupExport: Source Map is null.  Please report this bug to the Tpetra "
00518       "developers.");
00519     const Map<LO, GO, Node>& source = * (getSourceMap ());
00520 
00521     Teuchos::OSTab tab (out_);
00522 
00523     // if (debug_ && ! out_.is_null ()) {
00524     //   std::ostringstream os;
00525     //   const int myRank = source.getComm ()->getRank ();
00526     //   os << myRank << ": Import::setupExport:" << endl;
00527     // }
00528 
00529     // Sanity checks
00530     TEUCHOS_TEST_FOR_EXCEPTION(
00531       ! useRemotePIDs && (userRemotePIDs.size() > 0), std::invalid_argument,
00532       "Tpetra::Import::setupExport: remotePIDs are non-empty but their use has "
00533       "not been requested.");
00534     TEUCHOS_TEST_FOR_EXCEPTION(
00535       userRemotePIDs.size () > 0 && remoteGIDs.size () != userRemotePIDs.size (),
00536       std::invalid_argument, "Tpetra::Import::setupExport: remotePIDs must "
00537       "either be of size zero or match the size of remoteGIDs.");
00538 
00539     // For each entry remoteGIDs[i], remoteProcIDs[i] will contain
00540     // the process ID of the process that owns that GID.
00541     ArrayView<GO> remoteGIDsView = remoteGIDs ();
00542     ArrayView<int> remoteProcIDsView;
00543 
00544     // lookup == IDNotPresent means that the source Map wasn't able to
00545     // figure out to which processes one or more of the GIDs in the
00546     // given list of remote GIDs belong.
00547     //
00548     // The previous abuse warning said "The target Map has GIDs not
00549     // found in the source Map."  This statement could be confusing,
00550     // because it doesn't refer to ownership by the current process,
00551     // but rather to ownership by _any_ process participating in the
00552     // Map.  (It could not possibly refer to ownership by the current
00553     // process, since remoteGIDs is exactly the list of GIDs owned by
00554     // the target Map but not owned by the source Map.  It was
00555     // constructed that way by setupSamePermuteRemote().)
00556     //
00557     // What this statement means is that the source and target Maps
00558     // don't contain the same set of GIDs globally (over all
00559     // processes).  That is, there is at least one GID owned by some
00560     // process in the target Map, which is not owned by _any_ process
00561     // in the source Map.
00562     Array<int> newRemotePIDs;
00563     LookupStatus lookup = AllIDsPresent;
00564 
00565     if (! useRemotePIDs) {
00566       newRemotePIDs.resize (remoteGIDsView.size ());
00567       if (debug_ && ! out_.is_null ()) {
00568         std::ostringstream os;
00569         const int myRank = source.getComm ()->getRank ();
00570         os << myRank << ": Import::setupExport: about to call "
00571           "getRemoteIndexList on source Map" << endl;
00572         *out_ << os.str ();
00573       }
00574       lookup = source.getRemoteIndexList (remoteGIDsView, newRemotePIDs ());
00575     }
00576     Array<int>& remoteProcIDs = useRemotePIDs ? userRemotePIDs : newRemotePIDs;
00577 
00578     TPETRA_ABUSE_WARNING( lookup == IDNotPresent, std::runtime_error,
00579       "::setupExport(): the source Map wasn't able to figure out which process "
00580       "owns one or more of the GIDs in the list of remote GIDs.  This probably "
00581       "means that there is at least one GID owned by some process in the target"
00582       " Map which is not owned by any process in the source Map.  (That is, the"
00583       " source and target Maps do not contain the same set of GIDs globally.)");
00584 
00585     // Ignore remote GIDs that aren't owned by any process in the
00586     // source Map.  getRemoteIndexList() gives each of these a process
00587     // ID of -1.
00588     if (lookup == IDNotPresent) {
00589       const size_type numInvalidRemote =
00590         std::count_if (remoteProcIDs.begin (), remoteProcIDs.end (),
00591                        std::bind1st (std::equal_to<int> (), -1));
00592       // If all of them are invalid, we can delete the whole array.
00593       const size_type totalNumRemote = getNumRemoteIDs ();
00594       if (numInvalidRemote == totalNumRemote) {
00595         // all remotes are invalid; we have no remotes; we can delete the remotes
00596         remoteProcIDs.clear ();
00597         remoteGIDs.clear (); // This invalidates the view remoteGIDsView
00598         ImportData_->remoteLIDs_.clear();
00599       }
00600       else {
00601         // Some remotes are valid; we need to keep the valid ones.
00602         // Pack and resize remoteProcIDs, remoteGIDs, and remoteLIDs_.
00603         size_type numValidRemote = 0;
00604 #ifdef HAVE_TPETRA_DEBUG
00605         ArrayView<GlobalOrdinal> remoteGIDsPtr = remoteGIDsView;
00606 #else
00607         GlobalOrdinal* const remoteGIDsPtr = remoteGIDsView.getRawPtr ();
00608 #endif // HAVE_TPETRA_DEBUG
00609         for (size_type r = 0; r < totalNumRemote; ++r) {
00610           // Pack in all the valid remote PIDs and GIDs.
00611           if (remoteProcIDs[r] != -1) {
00612             remoteProcIDs[numValidRemote] = remoteProcIDs[r];
00613             remoteGIDsPtr[numValidRemote] = remoteGIDsPtr[r];
00614             ImportData_->remoteLIDs_[numValidRemote] = ImportData_->remoteLIDs_[r];
00615             ++numValidRemote;
00616           }
00617         }
00618         TEUCHOS_TEST_FOR_EXCEPTION(
00619           numValidRemote != totalNumRemote - numInvalidRemote, std::logic_error,
00620           "Tpetra::Import::setupExport(): After removing invalid remote GIDs and"
00621           " packing the valid remote GIDs, numValidRemote = " << numValidRemote
00622           << " != totalNumRemote - numInvalidRemote = "
00623           << totalNumRemote - numInvalidRemote
00624           << ".  Please report this bug to the Tpetra developers.");
00625 
00626         remoteProcIDs.resize (numValidRemote);
00627         remoteGIDs.resize (numValidRemote);
00628         ImportData_->remoteLIDs_.resize (numValidRemote);
00629       }
00630       // Revalidate the view after clear or resize.
00631       remoteGIDsView = remoteGIDs ();
00632     }
00633 
00634     // Sort remoteProcIDs in ascending order, and apply the resulting
00635     // permutation to remoteGIDs and remoteLIDs_.  This ensures that
00636     // remoteProcIDs[i], remoteGIDs[i], and remoteLIDs_[i] all refer
00637     // to the same thing.
00638     sort3 (remoteProcIDs.begin (),
00639            remoteProcIDs.end (),
00640            remoteGIDsView.begin (),
00641            ImportData_->remoteLIDs_.begin ());
00642 
00643     // Call the Distributor's createFromRecvs() method to turn the
00644     // remote GIDs and their owning processes into a send-and-receive
00645     // communication plan.  remoteGIDs and remoteProcIDs_ are input;
00646     // exportGIDs and exportProcIDs_ are output arrays which are
00647     // allocated by createFromRecvs().
00648     Array<GO> exportGIDs;
00649     ImportData_->distributor_.createFromRecvs (remoteGIDsView ().getConst (),
00650                                                remoteProcIDs, exportGIDs,
00651                                                ImportData_->exportPIDs_);
00652     // if (debug_ && ! out_.is_null ()) {
00653     //   std::ostringstream os;
00654     //   const int myRank = source.getComm ()->getRank ();
00655     //   os << myRank << ": Import::setupExport: Getting LIDs" << endl;
00656     //   *out_ << os.str ();
00657     // }
00658 
00659     // Find the LIDs corresponding to the (outgoing) GIDs in
00660     // exportGIDs.  For sparse matrix-vector multiply, this tells the
00661     // calling process how to index into the source vector to get the
00662     // elements which it needs to send.
00663     //
00664     // NOTE (mfh 03 Mar 2014) This is now a candidate for a
00665     // thread-parallel kernel, but only if using the new thread-safe
00666     // Map implementation.
00667     const size_type numExportIDs = exportGIDs.size ();
00668     if (numExportIDs > 0) {
00669       ImportData_->exportLIDs_.resize (numExportIDs);
00670       ArrayView<const GO> expGIDs = exportGIDs ();
00671       ArrayView<LO> expLIDs = ImportData_->exportLIDs_ ();
00672       for (size_type k = 0; k < numExportIDs; ++k) {
00673         expLIDs[k] = source.getLocalElement (expGIDs[k]);
00674       }
00675     }
00676 
00677     if (debug_ && ! out_.is_null ()) {
00678       std::ostringstream os;
00679       const int myRank = source.getComm ()->getRank ();
00680       os << myRank << ": Import::setupExport: done" << endl;
00681       *out_ << os.str ();
00682     }
00683   }
00684 
00685 
00686   template <class LocalOrdinal, class GlobalOrdinal, class Node>
00687   Teuchos::RCP<const Import<LocalOrdinal, GlobalOrdinal, Node> >
00688   Import<LocalOrdinal,GlobalOrdinal,Node>::
00689   setUnion (const Import<LocalOrdinal, GlobalOrdinal, Node>& rhs) const
00690   {
00691     typedef Tpetra::global_size_t GST;
00692     using Teuchos::Array;
00693     using Teuchos::ArrayView;
00694     using Teuchos::as;
00695     using Teuchos::Comm;
00696     using Teuchos::RCP;
00697     using Teuchos::rcp;
00698     using Teuchos::outArg;
00699     using Teuchos::REDUCE_MIN;
00700     using Teuchos::reduceAll;
00701     typedef LocalOrdinal LO;
00702     typedef GlobalOrdinal GO;
00703     typedef Import<LO, GO, Node> import_type;
00704     typedef typename Array<GO>::size_type size_type;
00705 
00706 #ifdef HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT
00707     using Teuchos::toString;
00708     using std::cerr;
00709     using std::endl;
00710 #endif // HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT
00711 
00712     RCP<const map_type> srcMap = this->getSourceMap ();
00713     RCP<const map_type> tgtMap1 = this->getTargetMap ();
00714     RCP<const map_type> tgtMap2 = rhs.getTargetMap ();
00715     RCP<const Comm<int> > comm = srcMap->getComm ();
00716 
00717 #ifdef HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT
00718     const int myRank = comm->getRank ();
00719 #endif // HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT
00720 
00721 #ifdef HAVE_TPETRA_DEBUG
00722     TEUCHOS_TEST_FOR_EXCEPTION(
00723       ! srcMap->isSameAs (* (rhs.getSourceMap ())), std::invalid_argument,
00724       "Tpetra::Import::setUnion: The source Map of the input Import must be the "
00725       "same as (in the sense of Map::isSameAs) the source Map of this Import.");
00726     TEUCHOS_TEST_FOR_EXCEPTION(
00727       ! Details::congruent (* (tgtMap1->getComm ()), * (tgtMap2->getComm ())),
00728       std::invalid_argument, "Tpetra::Import::setUnion: "
00729       "The target Maps must have congruent communicators.");
00730 #endif // HAVE_TPETRA_DEBUG
00731 
00732     // It's probably worth the one all-reduce to check whether the two
00733     // Maps are the same.  If so, we can just return a copy of *this.
00734     // isSameAs() bypasses the all-reduce if the pointers are equal.
00735     if (tgtMap1->isSameAs (*tgtMap2)) {
00736       return rcp (new import_type (*this));
00737     }
00738     // Alas, the two target Maps are not the same.  That means we have
00739     // to compute their union, and the union Import object.
00740 
00741     ArrayView<const GO> srcGIDs = srcMap->getNodeElementList ();
00742     ArrayView<const GO> tgtGIDs1 = tgtMap1->getNodeElementList ();
00743     ArrayView<const GO> tgtGIDs2 = tgtMap2->getNodeElementList ();
00744 
00745 #ifdef HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT
00746     comm->barrier ();
00747     {
00748       std::ostringstream os;
00749       os << myRank << ": srcGIDs: " << toString (srcGIDs) << endl;
00750       os << myRank << ": tgtGIDs1: " << toString (tgtGIDs1) << endl;
00751       os << myRank << ": tgtGIDs2: " << toString (tgtGIDs2) << endl;
00752       cerr << os.str ();
00753     }
00754     comm->barrier ();
00755 #endif // HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT
00756 
00757 
00758     // Fill this as we go with the union target Map's GIDs, in the
00759     // desired order.  We'll need them for the Map constructor.
00760     Array<GO> unionTgtGIDs;
00761     // Upper bound on the number of union target Map GIDs.  This
00762     // happens to be strict, but doesn't have to be.  Setting some
00763     // reasonable upper bound avoids reallocation in loops that do
00764     // push_back operations.
00765     unionTgtGIDs.reserve (tgtGIDs1.size () + tgtGIDs2.size ());
00766 
00767 #ifdef HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT
00768     if (myRank == 0) {
00769       cerr << endl;
00770     }
00771     comm->barrier ();
00772     comm->barrier ();
00773     comm->barrier ();
00774     cerr << myRank << ": Computing \"same\" GIDs" << endl;
00775 #endif // HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT
00776 
00777     // Compute the initial sequence of "same" GIDs in the union
00778     // import.  The number of "same" GIDs in the union is the maximum
00779     // of the lengths of this in the two inputs.
00780 
00781     const size_type numSameGIDs1 = this->getNumSameIDs ();
00782     const size_type numSameGIDs2 = rhs.getNumSameIDs ();
00783     ArrayView<const GO> sameGIDs1 = tgtGIDs1 (0, numSameGIDs1);
00784     ArrayView<const GO> sameGIDs2 = tgtGIDs2 (0, numSameGIDs2);
00785 #ifdef HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT
00786     {
00787       std::ostringstream os;
00788       os << myRank << ": same IDs for target Map 1: " << toString (sameGIDs1) << endl;
00789       os << myRank << ": same IDs for target Map 2: " << toString (sameGIDs2) << endl;
00790       cerr << os.str ();
00791     }
00792 #endif // HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT
00793     // For the input target Map with fewer "same" GIDs, that Map's
00794     // permute IDs could include some of the other input target Map's
00795     // "same" GIDs.  We have to make sure not to include them twice.
00796     // To do so, keep a view of them for now, and remove them (via set
00797     // intersection) from the permute ID list.  Keeping track of which
00798     // GID set had the max number of "same" IDs avoids unnecessary set
00799     // intersection operations later.
00800     ArrayView<const GO> doubleCountedSameGIDs;
00801     size_type numSameIDsUnion;
00802     bool tgtMap1HadMaxSameGIDs;
00803     if (numSameGIDs1 >= numSameGIDs2) {
00804       tgtMap1HadMaxSameGIDs = true;
00805       numSameIDsUnion = numSameGIDs1;
00806       std::copy (sameGIDs1.begin (), sameGIDs1.end (), std::back_inserter (unionTgtGIDs));
00807       // There could be GIDs in target Map 2 that are not included in
00808       // the "same" IDs, but are included in Import 2's permute IDs.
00809       // Keep track of them so we don't double-count them when
00810       // building the list of permute IDs.
00811       doubleCountedSameGIDs = tgtGIDs1 (numSameGIDs2, numSameGIDs1 - numSameGIDs2);
00812     } else {
00813       tgtMap1HadMaxSameGIDs = false;
00814       numSameIDsUnion = numSameGIDs2;
00815       std::copy (sameGIDs2.begin (), sameGIDs2.end (), std::back_inserter (unionTgtGIDs));
00816       // There could be GIDs in target Map 1 that are not included in
00817       // the "same" IDs, but are included in Import 1's permute IDs.
00818       // Keep track of them so we don't double-count them when
00819       // building the list of permute IDs.
00820       doubleCountedSameGIDs = tgtGIDs2 (numSameGIDs1, numSameGIDs2 - numSameGIDs1);
00821     }
00822 
00823 #ifdef HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT
00824     {
00825       std::ostringstream os;
00826       os << myRank << ": union Map's same GIDs: " << toString (unionTgtGIDs ()) << endl;
00827       os << myRank << ": doubleCountedSameGIDs: " << toString (doubleCountedSameGIDs) << endl;
00828       cerr << os.str ();
00829     }
00830     if (myRank == 0) {
00831       cerr << endl;
00832     }
00833     comm->barrier ();
00834     comm->barrier ();
00835     comm->barrier ();
00836     cerr << myRank << ": Computing permute IDs" << endl;
00837 #endif // HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT
00838 
00839     // Each input Import knows its permute-from LIDs (in the source
00840     // Map) and permute-to LIDs (in its target Map).  We will have to
00841     // reassign LIDs in the union target Map, but we can use these
00842     // permute-to LIDs to construct the union Import's permute-to IDs.
00843     Array<LO> permuteFromLIDsUnion;
00844     Array<LO> permuteToLIDsUnion;
00845     LO curTgtLid = as<LO> (numSameIDsUnion);
00846     {
00847       // Permute-to LIDs in the two input target Maps.
00848       ArrayView<const LO> permuteToLIDs1 = this->getPermuteToLIDs ();
00849       ArrayView<const LO> permuteToLIDs2 = rhs.getPermuteToLIDs ();
00850       const size_type numPermuteIDs1 = this->getNumPermuteIDs ();
00851       const size_type numPermuteIDs2 = rhs.getNumPermuteIDs ();
00852 
00853 #ifdef HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT
00854       cerr << myRank << ": Converting permute-to LIDs to GIDs" << endl;
00855 #endif // HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT
00856 
00857       // Convert the permute-to LID lists to GIDs, so that we can
00858       // later reassign LIDs for the (output) union target Map.
00859       Array<GO> permuteGIDs1 (numPermuteIDs1);
00860       for (size_type k = 0; k < numPermuteIDs1; ++k) {
00861         permuteGIDs1[k] = tgtMap1->getGlobalElement (permuteToLIDs1[k]);
00862       }
00863       Array<GO> permuteGIDs2 (numPermuteIDs2);
00864       for (size_type k = 0; k < numPermuteIDs2; ++k) {
00865         permuteGIDs2[k] = tgtMap2->getGlobalElement (permuteToLIDs2[k]);
00866       }
00867 
00868 #ifdef HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT
00869       {
00870         std::ostringstream os;
00871         os << myRank << ": permuteGIDs1: " << toString (permuteGIDs1) << endl;
00872         os << myRank << ": permuteGIDs2: " << toString (permuteGIDs2) << endl;
00873         cerr << os.str ();
00874       }
00875       cerr << myRank << ": Sorting and merging permute GID lists" << endl;
00876 #endif // HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT
00877 
00878       // Sort the two permute GID lists, remove the GIDs that we don't
00879       // want to double-count, and merge the result into the global
00880       // list of GIDs in the target union Map.
00881       std::sort (permuteGIDs1.begin (), permuteGIDs1.end ());
00882       std::sort (permuteGIDs2.begin (), permuteGIDs2.end ());
00883 
00884       typename Array<GO>::iterator permuteGIDs1_beg = permuteGIDs1.begin ();
00885       typename Array<GO>::iterator permuteGIDs1_end = permuteGIDs1.end ();
00886       typename Array<GO>::iterator permuteGIDs2_beg = permuteGIDs2.begin ();
00887       typename Array<GO>::iterator permuteGIDs2_end = permuteGIDs2.end ();
00888       if (tgtMap1HadMaxSameGIDs) {
00889         // This operation allows the last (output) argument to alias the first.
00890         permuteGIDs2_end =
00891           std::set_difference(permuteGIDs2_beg,
00892                               permuteGIDs2_end,
00893                               doubleCountedSameGIDs.begin (),
00894                               doubleCountedSameGIDs.end (),
00895                               permuteGIDs2_beg);
00896 
00897 
00898       } else {
00899         // This operation allows the last (output) argument to alias the first.
00900         permuteGIDs1_end =
00901           std::set_difference(permuteGIDs1_beg,
00902                               permuteGIDs1_end,
00903                               doubleCountedSameGIDs.begin (),
00904                               doubleCountedSameGIDs.end (),
00905                               permuteGIDs1_beg);
00906 
00907       }
00908       std::set_union (permuteGIDs1_beg, permuteGIDs1_end,
00909                       permuteGIDs2_beg, permuteGIDs2_end,
00910                       std::back_inserter (unionTgtGIDs));
00911 
00912 #ifdef HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT
00913       {
00914         std::ostringstream os;
00915         if(tgtMap1HadMaxSameGIDs) os << myRank << ": tgtMap1HadMaxSameGIDs == true"<<endl;
00916         else os << myRank << ": tgtMap1HadMaxSameGIDs == false"<<endl;
00917 
00918         os << myRank << ": reduced permuteGIDs1: {";
00919         for(typename Array<GO>::iterator k = permuteGIDs1_beg;  k != permuteGIDs1_end; k++)
00920           os<<*k<<", ";
00921         os<<"}"<<endl;
00922         os << myRank << ": reduced permuteGIDs2: {";
00923         for(typename Array<GO>::iterator k = permuteGIDs2_beg;  k != permuteGIDs2_end; k++)
00924           os<<*k<<", ";
00925         os<<"}"<<endl;
00926         cerr << os.str ();
00927       }
00928 #endif
00929       const size_type numPermuteIDsUnion =
00930         unionTgtGIDs.size () - numSameIDsUnion;
00931       ArrayView<const GO> permuteGIDsUnion =
00932         unionTgtGIDs (numSameIDsUnion, numPermuteIDsUnion).getConst ();
00933 
00934 #ifdef HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT
00935       {
00936         std::ostringstream os;
00937         os << myRank << ": permuteGIDsUnion: " << toString (permuteGIDsUnion) << endl;
00938         cerr << os.str ();
00939       }
00940 #endif // HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT
00941 
00942 #ifdef HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT
00943       comm->barrier ();
00944       cerr << myRank << ": Computing permute-to LIDs" << endl;
00945 #endif // HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT
00946 
00947       // Compute the permute-to LIDs (in the union target Map).
00948       permuteToLIDsUnion.resize (numPermuteIDsUnion);
00949       for (size_type k = 0; k < numPermuteIDsUnion; ++k) {
00950         permuteToLIDsUnion[k] = curTgtLid++;
00951       }
00952 
00953 #ifdef HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT
00954       {
00955         std::ostringstream os;
00956         os << myRank << ": permuteToLIDsUnion: " << toString (permuteToLIDsUnion) << endl;
00957         cerr << os.str ();
00958       }
00959 #endif // HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT
00960 
00961 #ifdef HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT
00962       comm->barrier ();
00963       cerr << myRank << ": Computing permute-from LIDs" << endl;
00964 #endif // HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT
00965 
00966       // Convert the permute GIDs to permute-from LIDs in the source Map.
00967       permuteFromLIDsUnion.resize (numPermuteIDsUnion);
00968       for (size_type k = 0; k < numPermuteIDsUnion; ++k) {
00969         permuteFromLIDsUnion[k] = srcMap->getLocalElement (permuteGIDsUnion[k]);
00970       }
00971 
00972 #ifdef HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT
00973       {
00974         std::ostringstream os;
00975         os << myRank << ": permuteFromLIDsUnion: " << toString (permuteFromLIDsUnion) << endl;
00976         cerr << os.str ();
00977       }
00978 #endif // HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT
00979     }// end permutes
00980 
00981 
00982 #ifdef HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT
00983     {
00984       std::ostringstream os;
00985       os << myRank << ": unionTgtGIDs after permutes: "
00986          << toString (unionTgtGIDs ()) << endl;
00987       cerr << os.str ();
00988     }
00989 #endif // HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT
00990 
00991     // Thus far, we have computed the following in the union Import:
00992     //   - getNumSameIDs()
00993     //   - getNumPermuteIDs()
00994     //   - getPermuteFromLIDs ()
00995     //   - getPermuteToLIDs ()
00996     //
00997     // Now it's time to compute the remote IDs.  By definition, none
00998     // of these IDs are in the source Map (on the calling process), so
00999     // they can't possibly overlap with any of the "same" or permute
01000     // IDs in either target Map.
01001     //
01002     // After the first numSameIDsUnion IDs, we get to control the
01003     // order of GIDs in the union target Map.  We'll put the permute
01004     // IDs first (which we already did above) and the remote IDs last
01005     // (which we are about to do).  We'll sort the remote IDs by
01006     // process rank, so that Distributor doesn't have to pack buffers.
01007     // (That way, doPosts() will always take the "fast path" on all
01008     // processes.)
01009 
01010 #ifdef HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT
01011     if (myRank == 0) {
01012       cerr << endl;
01013     }
01014     comm->barrier ();
01015     comm->barrier ();
01016     comm->barrier ();
01017     cerr << myRank << ": Computing remote IDs" << endl;
01018 #endif // HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT
01019 
01020     Array<GO> remoteGIDsUnion;
01021     Array<int> remotePIDsUnion;
01022     Array<LO> remoteLIDsUnion;
01023     size_type numRemoteIDsUnion = 0;
01024     {
01025       // Distributor::createFromRecvs takes remote IDs and PIDs as
01026       // input, and computes exportIDs and exportPIDs.  The easiest
01027       // way to get the remote PIDs is to imitate setupExport by using
01028       // getRemoteIndexList().  We could try to get them out of the
01029       // Distributor via getImagesFrom(), but Distributor reorders
01030       // them in some not entirely transparent way.
01031 
01032       // Grab the remoteLIDs
01033       ArrayView<const LO> remoteLIDs1 = this->getRemoteLIDs();
01034       ArrayView<const LO> remoteLIDs2 = rhs.getRemoteLIDs();
01035 
01036       // Grab the remotePIDs
01037       Array<int> remotePIDs1, remotePIDs2;
01038       Tpetra::Import_Util::getRemotePIDs(*this,remotePIDs1);
01039       Tpetra::Import_Util::getRemotePIDs(rhs,remotePIDs2);
01040 
01041       // Put the (PID,GID) into std:pairs to make for easier sorting
01042       Array<std::pair<int,GO> > remotePGIDs1, remotePGIDs2,remotePGUnion;
01043       remotePGIDs1.resize(remotePIDs1.size());
01044       remotePGIDs2.resize(remotePIDs2.size());
01045 
01046       for(size_type k=0; k < remotePIDs1.size(); k++)
01047         remotePGIDs1[k] = std::pair<int,GO>(remotePIDs1[k],this->getTargetMap()->getGlobalElement(remoteLIDs1[k]));
01048 
01049       for(size_type k=0; k < remotePIDs2.size(); k++)
01050         remotePGIDs2[k] = std::pair<int,GO>(remotePIDs2[k],rhs.getTargetMap()->getGlobalElement(remoteLIDs2[k]));
01051 
01052 
01053       // Sort and merge the (PID,GID) pairs (with the LIDs along for the ride at least for the sort)
01054       std::sort(remotePGIDs1.begin(), remotePGIDs1.end());
01055       std::sort(remotePGIDs2.begin(), remotePGIDs2.end());
01056       std::merge(remotePGIDs1.begin(), remotePGIDs1.end(),
01057                  remotePGIDs2.begin(), remotePGIDs2.end(),
01058                  std::back_inserter(remotePGUnion));
01059       typename Array<std::pair<int,GO> >::iterator it = std::unique(remotePGUnion.begin(),remotePGUnion.end());
01060       remotePGUnion.resize(std::distance(remotePGUnion.begin(),it));
01061 
01062       // Assign the remote LIDs in order; copy out
01063       numRemoteIDsUnion = remotePGUnion.size();
01064       remoteLIDsUnion.resize(numRemoteIDsUnion);
01065       remotePIDsUnion.resize(numRemoteIDsUnion);
01066       remoteGIDsUnion.resize(numRemoteIDsUnion);
01067 
01068       for (size_type k = 0; k < numRemoteIDsUnion; ++k) {
01069         remoteLIDsUnion[k] = curTgtLid++;
01070         remotePIDsUnion[k] = remotePGUnion[k].first;
01071         remoteGIDsUnion[k] = remotePGUnion[k].second;
01072       }
01073 
01074       // Update the unionTgtGIDs
01075       const size_type oldSize = unionTgtGIDs.size();
01076       unionTgtGIDs.resize(oldSize + numRemoteIDsUnion);
01077       for(size_type k=0; k<numRemoteIDsUnion; k++)
01078         unionTgtGIDs[oldSize+k] = remoteGIDsUnion[k];
01079 
01080 #ifdef HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT
01081       {
01082         // For debugging purposes only
01083         Array<GO> remoteGIDs1(remotePIDs1.size());
01084         Array<GO> remoteGIDs2(remotePIDs2.size());
01085         for(size_type k=0; k < remotePIDs1.size(); k++)
01086           remoteGIDs1[k] = this->getTargetMap()->getGlobalElement(remoteLIDs1[k]);
01087         for(size_type k=0; k < remotePIDs2.size(); k++)
01088           remoteGIDs2[k] = rhs.getTargetMap()->getGlobalElement(remoteLIDs2[k]);
01089 
01090         std::ostringstream os;
01091         os << myRank << ": remoteGIDs1           : " << toString (remoteGIDs1 ()) << endl;
01092         os << myRank << ": remotePIDs1           : " << toString (remotePIDs1 ()) << endl;
01093         os << myRank << ": remoteGIDs2           : " << toString (remoteGIDs2 ()) << endl;
01094         os << myRank << ": remotePIDs2           : " << toString (remotePIDs2 ()) << endl;
01095         cerr << os.str ();
01096       }
01097 #endif
01098     }//end remotes
01099 
01100 #ifdef HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT
01101       {
01102         std::ostringstream os;
01103         os << myRank << ": remoteGIDsUnion sorted: " << toString (remoteGIDsUnion ()) << endl;
01104         os << myRank << ": remotePIDsUnion sorted: " << toString (remotePIDsUnion ()) << endl;
01105         os << myRank << ": remoteLIDsUnion sorted: " << toString (remoteLIDsUnion ()) << endl;
01106         cerr << os.str ();
01107       }
01108 #endif // HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT
01109 
01110 
01111 #ifdef HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT
01112     {
01113       std::ostringstream os;
01114       os << myRank << ": unionTgtGIDs after remotes: "
01115          << toString (unionTgtGIDs ()) << endl;
01116       cerr << os.str ();
01117     }
01118 #endif // HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT
01119 
01120     // Find the union target Map's index base, which must also be the
01121     // union target Map's global min GID.  Thus, by definition, it
01122     // must be the minimum of the two input target Maps' index bases.
01123     // We already know these, so we don't have to do another
01124     // all-reduce to find it.
01125     const GO indexBaseUnion =
01126       std::min (tgtMap1->getIndexBase (), tgtMap2->getIndexBase ());
01127 
01128 #ifdef HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT
01129     cerr << myRank << "Creating union target Map" << endl;
01130 #endif // HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT
01131 
01132     // Create the union target Map.
01133     //
01134     // mfh 01 May 2013, 28 Feb 2014: It might be handy to have a Map
01135     // constructor that takes the global min and max GIDs; that would
01136     // obviate the need for Map to compute them.  On the other hand,
01137     // for signed GlobalOrdinal, this version of Map's constructor
01138     // already computes as few all-reduces as possible (not including
01139     // optimizations that might be possible if one were to fold in
01140     // Directory construction).  The constructor must do two
01141     // all-reduces:
01142     //
01143     //   1. Get the global number of GIDs (since the first argument is
01144     //      INVALID, we're asking Map to compute this for us)
01145     //
01146     //   2. Figure out three things: global min and max GID, and
01147     //      whether the Map is distributed or locally replicated.
01148     //
01149     // #2 above happens in one all-reduce (of three integers).
01150     // #Figuring out whether the Map is distributed or locally
01151     // #replicated requires knowing the global number of GIDs.
01152     const GST INVALID = Teuchos::OrdinalTraits<GST>::invalid ();
01153     RCP<const map_type> unionTgtMap =
01154       rcp (new map_type (INVALID, unionTgtGIDs (), indexBaseUnion,
01155                          comm, srcMap->getNode ()));
01156 
01157 #ifdef HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT
01158     if (myRank == 0) {
01159       cerr << endl;
01160     }
01161     comm->barrier ();
01162     comm->barrier ();
01163     comm->barrier ();
01164     cerr << myRank << ": Computing export IDs and Distributor" << endl;
01165 #endif // HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT
01166 
01167     // Thus far, we have computed the following in the union Import:
01168     //   - numSameIDs
01169     //   - numPermuteIDs and permuteFromLIDs
01170     //   - numRemoteIDs, remoteGIDs, remoteLIDs, and remotePIDs
01171     //
01172     // Now it's time to compute the export IDs and initialize the
01173     // Distributor.
01174 
01175     Array<GO> exportGIDsUnion;
01176     Array<LO> exportLIDsUnion;
01177     Array<int> exportPIDsUnion;
01178     Distributor distributor (comm, this->out_);
01179 
01180 #ifdef TPETRA_IMPORT_SETUNION_USE_CREATE_FROM_SENDS
01181     // Compute the export IDs without communication, by merging the
01182     // lists of (export LID, export PID) pairs from the two input
01183     // Import objects.  The export LIDs in both input Import objects
01184     // are LIDs in the source Map.  Then, use the export PIDs to
01185     // initialize the Distributor via createFromSends.
01186 
01187     // const size_type numExportIDs1 = this->getNumExportIDs ();
01188     ArrayView<const LO> exportLIDs1 = this->getExportLIDs ();
01189     ArrayView<const LO> exportPIDs1 = this->getExportPIDs ();
01190 
01191     // const size_type numExportIDs2 = rhs.getNumExportIDs ();
01192     ArrayView<const LO> exportLIDs2 = rhs.getExportLIDs ();
01193     ArrayView<const LO> exportPIDs2 = rhs.getExportPIDs ();
01194 
01195     // We have to keep the export LIDs in PID-sorted order, then merge
01196     // them.  So, first key-value merge (LID,PID) pairs, treating PIDs
01197     // as values, merging values by replacement.  Then, sort the
01198     // (LID,PID) pairs again by PID.
01199 
01200     // Sort (LID,PID) pairs by LID for the later merge, and make
01201     // each sequence unique by LID.
01202     Array<LO> exportLIDs1Copy (exportLIDs1.begin (), exportLIDs1.end ());
01203     Array<int> exportPIDs1Copy (exportLIDs1.begin (), exportLIDs1.end ());
01204     sort2 (exportLIDs1Copy.begin (), exportLIDs1Copy.end (),
01205            exportPIDs1Copy.begin ());
01206     typename ArrayView<LO>::iterator exportLIDs1_end = exportLIDs1Copy.end ();
01207     typename ArrayView<LO>::iterator exportPIDs1_end = exportPIDs1Copy.end ();
01208     merge2 (exportLIDs1_end, exportPIDs1_end,
01209             exportLIDs1Copy.begin (), exportLIDs1_end,
01210             exportPIDs1Copy.begin (), exportPIDs1_end,
01211             project1st<LO, LO> ());
01212 
01213     Array<LO> exportLIDs2Copy (exportLIDs2.begin (), exportLIDs2.end ());
01214     Array<int> exportPIDs2Copy (exportLIDs2.begin (), exportLIDs2.end ());
01215     sort2 (exportLIDs2Copy.begin (), exportLIDs2Copy.end (),
01216            exportPIDs2Copy.begin ());
01217     typename ArrayView<LO>::iterator exportLIDs2_end = exportLIDs2Copy.end ();
01218     typename ArrayView<LO>::iterator exportPIDs2_end = exportPIDs2Copy.end ();
01219     merge2 (exportLIDs2_end, exportPIDs2_end,
01220             exportLIDs2Copy.begin (), exportLIDs2_end,
01221             exportPIDs2Copy.begin (), exportPIDs2_end,
01222             project1st<LO, LO> ());
01223 
01224     // Merge export (LID,PID) pairs.  In this merge operation, the
01225     // LIDs are the "keys" and the PIDs their "values."  We combine
01226     // the "values" (PIDs) in the pairs by replacement, rather than
01227     // by adding them together.
01228     keyValueMerge (exportLIDs1Copy.begin (), exportLIDs1Copy.end (),
01229                    exportPIDs1Copy.begin (), exportPIDs1Copy.end (),
01230                    exportLIDs2Copy.begin (), exportLIDs2Copy.end (),
01231                    exportPIDs2Copy.begin (), exportPIDs2Copy.end (),
01232                    std::back_inserter (exportLIDsUnion),
01233                    std::back_inserter (exportPIDsUnion),
01234                    project1st<int, int> ());
01235 
01236     // Resort the merged (LID,PID) pairs by PID.
01237     sort2 (exportPIDsUnion.begin (), exportPIDsUnion.end (),
01238            exportLIDsUnion.begin ());
01239 
01240     // Initialize the Distributor.  Using createFromSends instead of
01241     // createFromRecvs avoids the initialization and use of a
01242     // temporary Distributor object.
01243     (void) distributor.createFromSends (exportPIDsUnion ().getConst ());
01244 #else // NOT TPETRA_IMPORT_SETUNION_USE_CREATE_FROM_SENDS
01245 
01246     // Call the Distributor's createFromRecvs() method to turn the
01247     // remote GIDs and their owning processes into a send-and-receive
01248     // communication plan.  remoteGIDsUnion and remotePIDsUnion are
01249     // input; exportGIDsUnion and exportPIDsUnion are output arrays
01250     // which are allocated by createFromRecvs().
01251     distributor.createFromRecvs (remoteGIDsUnion().getConst (),
01252                                  remotePIDsUnion ().getConst (),
01253                                  exportGIDsUnion, exportPIDsUnion);
01254 
01255     // Find the (source Map) LIDs corresponding to the export GIDs.
01256     const size_type numExportIDsUnion = exportGIDsUnion.size ();
01257     exportLIDsUnion.resize (numExportIDsUnion);
01258     for (size_type k = 0; k < numExportIDsUnion; ++k) {
01259       exportLIDsUnion[k] = srcMap->getLocalElement (exportGIDsUnion[k]);
01260     }
01261 #endif // TPETRA_IMPORT_SETUNION_USE_CREATE_FROM_SENDS
01262 
01263 #ifdef HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT
01264     {
01265       std::ostringstream os;
01266       os << myRank << ": exportGIDsUnion: " << toString (exportGIDsUnion ()) << endl;
01267       os << myRank << ": exportPIDsUnion: " << toString (exportPIDsUnion ()) << endl;
01268       os << myRank << ": exportLIDsUnion: " << toString (exportLIDsUnion ()) << endl;
01269       cerr << os.str ();
01270     }
01271     comm->barrier ();
01272     cerr << "Creating union Import" << endl;
01273 #endif // HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT
01274 
01275     // Create and return the union Import.
01276     RCP<const import_type> unionImport =
01277       rcp (new import_type (srcMap, unionTgtMap,
01278                             as<size_t> (numSameIDsUnion),
01279                             permuteToLIDsUnion, permuteFromLIDsUnion,
01280                             remoteLIDsUnion, exportLIDsUnion,
01281                             exportPIDsUnion, distributor, this->out_));
01282 #ifdef HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT
01283     comm->barrier ();
01284     cerr << "Created union Import; done!" << endl;
01285 #endif // HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT
01286 
01287     return unionImport;
01288   }
01289 
01290 
01291 
01292   template <class LocalOrdinal, class GlobalOrdinal, class Node>
01293   Teuchos::RCP<const Import<LocalOrdinal, GlobalOrdinal, Node> >
01294   Import<LocalOrdinal,GlobalOrdinal,Node>::
01295   setUnion () const
01296   {
01297     using Teuchos::Array;
01298     using Teuchos::ArrayView;
01299     using Teuchos::as;
01300     using Teuchos::Comm;
01301     using Teuchos::RCP;
01302     using Teuchos::rcp;
01303     using Teuchos::outArg;
01304     using Teuchos::REDUCE_MIN;
01305     using Teuchos::reduceAll;
01306     typedef LocalOrdinal LO;
01307     typedef GlobalOrdinal GO;
01308     Teuchos::RCP<const Import<LocalOrdinal, GlobalOrdinal, Node> > unionImport;
01309     RCP<const map_type> srcMap = this->getSourceMap ();
01310     RCP<const map_type> tgtMap = this->getTargetMap ();
01311     RCP<const Comm<int> > comm = srcMap->getComm ();
01312 
01313 #ifdef HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT
01314     const int myRank = comm->getRank ();
01315 #endif // HAVE_TPETRA_IMPORT_SETUNION_EXTRA_DEBUG_OUTPUT
01316 
01317     ArrayView<const GO> srcGIDs = srcMap->getNodeElementList ();
01318     ArrayView<const GO> tgtGIDs = tgtMap->getNodeElementList ();
01319 
01320     // All elements in srcMap will be in the "new" target map, so...
01321     size_t numSameIDsNew    = srcMap->getNodeNumElements();
01322     size_t numRemoteIDsNew  = getNumRemoteIDs();
01323     Array<LO> permuteToLIDsNew, permuteFromLIDsNew; // empty on purpose
01324 
01325     // Grab some old data
01326     ArrayView<const LO> remoteLIDsOld = getRemoteLIDs();
01327     ArrayView<const LO> exportLIDsOld = getExportLIDs();
01328 
01329     // Build up the new map (same part)
01330     Array<GO> GIDs(numSameIDsNew + numRemoteIDsNew);
01331     for(size_t i=0; i<numSameIDsNew; i++)
01332       GIDs[i] = srcGIDs[i];
01333 
01334     // Build up the new map (remote part) and remotes list
01335     Array<LO> remoteLIDsNew(numRemoteIDsNew);
01336     for(size_t i=0; i<numRemoteIDsNew; i++) {
01337       GIDs[numSameIDsNew + i] = tgtGIDs[remoteLIDsOld[i]];
01338       remoteLIDsNew[i] = numSameIDsNew+i;
01339     }
01340 
01341     // Build the new target map
01342     GO GO_INVALID = Teuchos::OrdinalTraits<GO>::invalid();
01343     RCP<const map_type> targetMapNew = rcp(new map_type(GO_INVALID,GIDs,tgtMap->getIndexBase(),tgtMap->getComm(),tgtMap->getNode()));
01344 
01345     // Exports are trivial (since the sourcemap doesn't change)
01346     Array<int> exportPIDsnew(getExportPIDs());
01347     Array<LO> exportLIDsnew(getExportLIDs());
01348 
01349     // Copy the Distributor (due to how the Import constructor works)
01350     Distributor D(getDistributor());
01351 
01352     // Build the importer
01353     unionImport = rcp(new Import<LocalOrdinal, GlobalOrdinal, Node>(srcMap,targetMapNew,numSameIDsNew,permuteToLIDsNew,permuteFromLIDsNew,
01354                                                                     remoteLIDsNew,exportLIDsnew,exportPIDsnew,D));
01355 
01356     return unionImport;
01357   }
01358 
01359 
01360 
01361 
01362   template <class LocalOrdinal, class GlobalOrdinal, class Node>
01363   Teuchos::RCP<const Import<LocalOrdinal, GlobalOrdinal, Node> >
01364   Import<LocalOrdinal,GlobalOrdinal,Node>::
01365   createRemoteOnlyImport(const Teuchos::RCP<const map_type>& remoteTarget) const
01366   {
01367     size_t NumRemotes = getNumRemoteIDs();
01368     // Sanity Check
01369     if(NumRemotes != remoteTarget->getNodeNumElements())
01370       throw std::runtime_error("createRemoteOnlyImporter: remoteTarget map ID count doesn't match.");
01371 
01372     // Compute the new Remote LIDs
01373     Teuchos::ArrayView<const LocalOrdinal> oldRemoteLIDs = getRemoteLIDs();
01374     Teuchos::Array<LocalOrdinal>           newRemoteLIDs(NumRemotes);
01375     for(size_t i=0; i < NumRemotes; i++) {
01376       newRemoteLIDs[i] = remoteTarget->getLocalElement(getTargetMap()->getGlobalElement(oldRemoteLIDs[i]));
01377 
01378       // Now we make sure these guys are in sorted order (AztecOO-ML ordering)
01379       if(i>0 && newRemoteLIDs[i] < newRemoteLIDs[i-1])
01380         throw std::runtime_error("createRemoteOnlyImporter: this and remoteTarget order don't match.");
01381     }
01382 
01383     // Copy ExportPIDs and such
01384     // NOTE: Be careful: The Import constructor we use does a "swap" for most of the LID/PID lists and the Distributor, meaning it
01385     // ruins the existing object if we pass things in directly.  Hence we copy them first.
01386     Teuchos::Array<int> newExportPIDs(getExportPIDs());
01387     Teuchos::Array<int> newExportLIDs(getExportLIDs());
01388     Teuchos::Array<LocalOrdinal> dummy;
01389     Teuchos::RCP<const Import<LocalOrdinal, GlobalOrdinal, Node> > newImport;
01390     Distributor newDistor(getDistributor());
01391 
01392     newImport = Teuchos::rcp(new Import<LocalOrdinal,GlobalOrdinal,Node>(getSourceMap(),remoteTarget,
01393                                                                          Teuchos::as<size_t>(0),
01394                                                                          dummy,
01395                                                                          dummy,
01396                                                                          newRemoteLIDs,
01397                                                                          newExportLIDs,
01398                                                                          newExportPIDs,
01399                                                                          newDistor));
01400     return newImport;
01401   }
01402 
01403 } // namespace Tpetra
01404 
01405 // Explicit instantiation macro.
01406 // Only invoke this when in the Tpetra namespace.
01407 // Most users do not need to use this.
01408 //
01409 // LO: The local ordinal type.
01410 // GO: The global ordinal type.
01411 // NODE: The Kokkos Node type.
01412 #define TPETRA_IMPORT_INSTANT(LO, GO, NODE) \
01413   \
01414   template class Import< LO , GO , NODE >;
01415 
01416 #endif // TPETRA_IMPORT_DEF_HPP
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines