Tpetra Matrix/Vector Services  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
Tpetra_KokkosRefactor_DistObject_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_KOKKOS_REFACTOR_DISTOBJECT_DEF_HPP
00043 #define TPETRA_KOKKOS_REFACTOR_DISTOBJECT_DEF_HPP
00044 
00045 #include "Tpetra_ConfigDefs.hpp"
00046 #include "Tpetra_Map.hpp"
00047 #include "Tpetra_Import.hpp"
00048 #include "Tpetra_Export.hpp"
00049 #include "Tpetra_Distributor.hpp"
00050 
00051 #ifdef DOXYGEN_USE_ONLY
00052 #  include "Tpetra_DistObject_decl.hpp"
00053 #endif // DOXYGEN_USE_ONLY
00054 
00055 namespace Tpetra {
00056   template <class Packet, class LocalOrdinal, class GlobalOrdinal, class Device>
00057   DistObject<Packet,LocalOrdinal,GlobalOrdinal,Kokkos::Compat::KokkosDeviceWrapperNode<Device> >::
00058   DistObject (const Teuchos::RCP<const Map<LocalOrdinal,GlobalOrdinal,Node> >& map)
00059     : map_ (map)
00060   {
00061 #ifdef HAVE_TPETRA_TRANSFER_TIMERS
00062     using Teuchos::RCP;
00063     using Teuchos::Time;
00064     using Teuchos::TimeMonitor;
00065 
00066     RCP<Time> doXferTimer =
00067       TimeMonitor::lookupCounter ("Tpetra::DistObject::doTransfer");
00068     if (doXferTimer.is_null ()) {
00069       doXferTimer =
00070         TimeMonitor::getNewCounter ("Tpetra::DistObject::doTransfer");
00071     }
00072     doXferTimer_ = doXferTimer;
00073 
00074     RCP<Time> copyAndPermuteTimer =
00075       TimeMonitor::lookupCounter ("Tpetra::DistObject::copyAndPermute");
00076     if (copyAndPermuteTimer.is_null ()) {
00077       copyAndPermuteTimer =
00078         TimeMonitor::getNewCounter ("Tpetra::DistObject::copyAndPermute");
00079     }
00080     copyAndPermuteTimer_ = copyAndPermuteTimer;
00081 
00082     RCP<Time> packAndPrepareTimer =
00083       TimeMonitor::lookupCounter ("Tpetra::DistObject::packAndPrepare");
00084     if (packAndPrepareTimer.is_null ()) {
00085       packAndPrepareTimer =
00086         TimeMonitor::getNewCounter ("Tpetra::DistObject::packAndPrepare");
00087     }
00088     packAndPrepareTimer_ = packAndPrepareTimer;
00089 
00090     RCP<Time> doPostsAndWaitsTimer =
00091       TimeMonitor::lookupCounter ("Tpetra::DistObject::doPostsAndWaits");
00092     if (doPostsAndWaitsTimer.is_null ()) {
00093       doPostsAndWaitsTimer =
00094         TimeMonitor::getNewCounter ("Tpetra::DistObject::doPostsAndWaits");
00095     }
00096     doPostsAndWaitsTimer_ = doPostsAndWaitsTimer;
00097 
00098     RCP<Time> unpackAndCombineTimer =
00099       TimeMonitor::lookupCounter ("Tpetra::DistObject::unpackAndCombine");
00100     if (unpackAndCombineTimer.is_null ()) {
00101       unpackAndCombineTimer =
00102         TimeMonitor::getNewCounter ("Tpetra::DistObject::unpackAndCombine");
00103     }
00104     unpackAndCombineTimer_ = unpackAndCombineTimer;
00105 #endif // HAVE_TPETRA_TRANSFER_TIMERS
00106   }
00107 
00108   template <class Packet, class LocalOrdinal, class GlobalOrdinal, class Device>
00109   DistObject<Packet,LocalOrdinal,GlobalOrdinal,Kokkos::Compat::KokkosDeviceWrapperNode<Device> >::
00110   DistObject (const DistObject<Packet,LocalOrdinal,GlobalOrdinal,Node>& rhs)
00111     : map_ (rhs.map_)
00112   {}
00113 
00114   template <class Packet, class LocalOrdinal, class GlobalOrdinal, class Device>
00115   DistObject<Packet,LocalOrdinal,GlobalOrdinal,Kokkos::Compat::KokkosDeviceWrapperNode<Device> >::~DistObject()
00116   {}
00117 
00118   template <class Packet, class LocalOrdinal, class GlobalOrdinal, class Device>
00119   std::string
00120   DistObject<Packet,LocalOrdinal,GlobalOrdinal,Kokkos::Compat::KokkosDeviceWrapperNode<Device> >::description () const
00121   {
00122     using Teuchos::TypeNameTraits;
00123 
00124     std::ostringstream os;
00125     os << "\"Tpetra::DistObject\": {"
00126        << "Packet: " << TypeNameTraits<Packet>::name ()
00127        << ", LocalOrdinal: " << TypeNameTraits<LocalOrdinal>::name ()
00128        << ", GlobalOrdinal: " << TypeNameTraits<GlobalOrdinal>::name ()
00129        << ", Node: " << TypeNameTraits<Node>::name ();
00130     if (this->getObjectLabel () != "") {
00131       os << "Label: \"" << this->getObjectLabel () << "\"";
00132     }
00133     os << "}";
00134     return os.str ();
00135   }
00136 
00137   template <class Packet, class LocalOrdinal, class GlobalOrdinal, class Device>
00138   void
00139   DistObject<Packet,LocalOrdinal,GlobalOrdinal,Kokkos::Compat::KokkosDeviceWrapperNode<Device> >::
00140   describe (Teuchos::FancyOStream &out,
00141             const Teuchos::EVerbosityLevel verbLevel) const
00142   {
00143     using Teuchos::rcpFromRef;
00144     using Teuchos::TypeNameTraits;
00145     using std::endl;
00146     const Teuchos::EVerbosityLevel vl = (verbLevel == Teuchos::VERB_DEFAULT) ?
00147       Teuchos::VERB_LOW : verbLevel;
00148     Teuchos::RCP<const Teuchos::Comm<int> > comm = this->getMap ()->getComm ();
00149     const int myRank = comm.is_null () ? 0 : comm->getRank ();
00150     const int numProcs = comm.is_null () ? 1 : comm->getSize ();
00151 
00152     if (vl != Teuchos::VERB_NONE) {
00153       Teuchos::OSTab tab0 (out);
00154       if (myRank == 0) {
00155         out << "\"Tpetra::DistObject\":" << endl;
00156       }
00157       Teuchos::OSTab tab1 (out);
00158       if (myRank == 0) {
00159         out << "Template parameters:" << endl;
00160         {
00161           Teuchos::OSTab tab2 (out);
00162           out << "Packet: " << TypeNameTraits<Packet>::name () << endl
00163               << "LocalOrdinal: " << TypeNameTraits<LocalOrdinal>::name () << endl
00164               << "GlobalOrdinal: " << TypeNameTraits<GlobalOrdinal>::name () << endl
00165               << "Node: " << TypeNameTraits<Node>::name () << endl;
00166         }
00167         if (this->getObjectLabel () != "") {
00168           out << "Label: \"" << this->getObjectLabel () << "\"" << endl;
00169         }
00170       } // if myRank == 0
00171 
00172       // Describe the Map.
00173       {
00174         if (myRank == 0) {
00175           out << "Map:" << endl;
00176         }
00177         Teuchos::OSTab tab2 (out);
00178         map_->describe (out, vl);
00179       }
00180 
00181       // At verbosity > VERB_LOW, each process prints something.
00182       if (vl > Teuchos::VERB_LOW) {
00183         for (int p = 0; p < numProcs; ++p) {
00184           if (myRank == p) {
00185             out << "Process " << myRank << ":" << endl;
00186             Teuchos::OSTab tab2 (out);
00187             out << "Export buffer size (in packets): " << exports_.size ()
00188                 << endl
00189                 << "Import buffer size (in packets): " << imports_.size ()
00190                 << endl;
00191           }
00192           if (! comm.is_null ()) {
00193             comm->barrier (); // give output time to finish
00194             comm->barrier ();
00195             comm->barrier ();
00196           }
00197         } // for each process rank p
00198       } // if vl > VERB_LOW
00199     } // if vl != VERB_NONE
00200   }
00201 
00202   template <class Packet, class LocalOrdinal, class GlobalOrdinal, class Device>
00203   void
00204   DistObject<Packet, LocalOrdinal, GlobalOrdinal, Kokkos::Compat::KokkosDeviceWrapperNode<Device> >::
00205   removeEmptyProcessesInPlace (const Teuchos::RCP<const Map<LocalOrdinal, GlobalOrdinal, Node> >& newMap)
00206   {
00207     TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error,
00208       "Tpetra::DistObject::removeEmptyProcessesInPlace: Not implemented");
00209   }
00210 
00211   /* These are provided in base DistObject template
00212   template<class DistObjectType>
00213   void
00214   removeEmptyProcessesInPlace (Teuchos::RCP<DistObjectType>& input,
00215                                const Teuchos::RCP<const Map<typename DistObjectType::local_ordinal_type,
00216                                                             typename DistObjectType::global_ordinal_type,
00217                                                             typename DistObjectType::node_type> >& newMap)
00218   {
00219     input->removeEmptyProcessesInPlace (newMap);
00220     if (newMap.is_null ()) { // my process is excluded
00221       input = Teuchos::null;
00222     }
00223   }
00224 
00225   template<class DistObjectType>
00226   void
00227   removeEmptyProcessesInPlace (Teuchos::RCP<DistObjectType>& input)
00228   {
00229     using Teuchos::RCP;
00230     typedef typename DistObjectType::local_ordinal_type LO;
00231     typedef typename DistObjectType::global_ordinal_type GO;
00232     typedef typename DistObjectType::node_type NT;
00233     typedef Map<LO, GO, NT> map_type;
00234 
00235     RCP<const map_type> newMap = input->getMap ()->removeEmptyProcesses ();
00236     removeEmptyProcessesInPlace<DistObjectType> (input, newMap);
00237   }
00238   */
00239 
00240   template <class Packet, class LocalOrdinal, class GlobalOrdinal, class Device>
00241   void
00242   DistObject<Packet,LocalOrdinal,GlobalOrdinal,Kokkos::Compat::KokkosDeviceWrapperNode<Device> >::
00243   doImport (const SrcDistObject& source,
00244             const Import<LocalOrdinal,GlobalOrdinal,Node>& importer,
00245             CombineMode CM)
00246   {
00247     TEUCHOS_TEST_FOR_EXCEPTION(*getMap() != *importer.getTargetMap(),
00248       std::invalid_argument, "doImport: The target DistObject's Map is not "
00249       "identical to the Import's target Map.");
00250 #ifdef HAVE_TPETRA_DEBUG
00251     {
00252       typedef DistObject<Packet,LocalOrdinal,GlobalOrdinal,Node> this_type;
00253       const this_type* srcDistObj = dynamic_cast<const this_type*> (&source);
00254       TEUCHOS_TEST_FOR_EXCEPTION(
00255         srcDistObj != NULL && * (srcDistObj->getMap ()) != *importer.getSourceMap(),
00256         std::invalid_argument, "doImport: The source is a DistObject, yet its "
00257         "Map is not identical to the Import's source Map.");
00258     }
00259 #endif // HAVE_TPETRA_DEBUG
00260     size_t numSameIDs = importer.getNumSameIDs ();
00261 
00262     typedef Teuchos::ArrayView<const LocalOrdinal> view_type;
00263     const view_type exportLIDs      = importer.getExportLIDs();
00264     const view_type remoteLIDs      = importer.getRemoteLIDs();
00265     const view_type permuteToLIDs   = importer.getPermuteToLIDs();
00266     const view_type permuteFromLIDs = importer.getPermuteFromLIDs();
00267     this->doTransfer (source, CM, numSameIDs, permuteToLIDs, permuteFromLIDs,
00268                       remoteLIDs, exportLIDs, importer.getDistributor (),
00269                       DoForward);
00270   }
00271 
00272   template <class Packet, class LocalOrdinal, class GlobalOrdinal, class Device>
00273   void
00274   DistObject<Packet,LocalOrdinal,GlobalOrdinal,Kokkos::Compat::KokkosDeviceWrapperNode<Device> >::
00275   doExport (const SrcDistObject& source,
00276             const Export<LocalOrdinal,GlobalOrdinal,Node>& exporter,
00277             CombineMode CM)
00278   {
00279     TEUCHOS_TEST_FOR_EXCEPTION(
00280       *getMap() != *exporter.getTargetMap(), std::invalid_argument,
00281       "doExport: The target DistObject's Map is not identical to the Export's "
00282       "target Map.");
00283 #ifdef HAVE_TPETRA_DEBUG
00284     {
00285       typedef DistObject<Packet,LocalOrdinal,GlobalOrdinal,Node> this_type;
00286       const this_type* srcDistObj = dynamic_cast<const this_type*> (&source);
00287       TEUCHOS_TEST_FOR_EXCEPTION(
00288         srcDistObj != NULL && * (srcDistObj->getMap ()) != *exporter.getSourceMap(),
00289         std::invalid_argument, "doExport: The source is a DistObject, yet its "
00290         "Map is not identical to the Export's source Map.");
00291     }
00292 #endif // HAVE_TPETRA_DEBUG
00293     size_t numSameIDs = exporter.getNumSameIDs();
00294 
00295     typedef ArrayView<const LocalOrdinal> view_type;
00296     view_type exportLIDs      = exporter.getExportLIDs();
00297     view_type remoteLIDs      = exporter.getRemoteLIDs();
00298     view_type permuteToLIDs   = exporter.getPermuteToLIDs();
00299     view_type permuteFromLIDs = exporter.getPermuteFromLIDs();
00300     doTransfer (source, CM, numSameIDs, permuteToLIDs, permuteFromLIDs, remoteLIDs,
00301                 exportLIDs, exporter.getDistributor (), DoForward);
00302   }
00303 
00304   template <class Packet, class LocalOrdinal, class GlobalOrdinal, class Device>
00305   void
00306   DistObject<Packet,LocalOrdinal,GlobalOrdinal,Kokkos::Compat::KokkosDeviceWrapperNode<Device> >::
00307   doImport (const SrcDistObject& source,
00308             const Export<LocalOrdinal,GlobalOrdinal,Node> & exporter,
00309             CombineMode CM)
00310   {
00311     TEUCHOS_TEST_FOR_EXCEPTION(
00312       *getMap() != *exporter.getSourceMap(), std::invalid_argument,
00313       "doImport (reverse mode): The target DistObject's Map is not identical "
00314       "to the Export's source Map.");
00315 #ifdef HAVE_TPETRA_DEBUG
00316     {
00317       typedef DistObject<Packet,LocalOrdinal,GlobalOrdinal,Node> this_type;
00318       const this_type* srcDistObj = dynamic_cast<const this_type*> (&source);
00319       TEUCHOS_TEST_FOR_EXCEPTION(
00320         srcDistObj != NULL && * (srcDistObj->getMap ()) != *exporter.getTargetMap(),
00321         std::invalid_argument,
00322         "doImport (reverse mode): The source is a DistObject, yet its "
00323         "Map is not identical to the Export's target Map.");
00324     }
00325 #endif // HAVE_TPETRA_DEBUG
00326     size_t numSameIDs = exporter.getNumSameIDs();
00327 
00328     typedef ArrayView<const LocalOrdinal> view_type;
00329     view_type exportLIDs      = exporter.getRemoteLIDs();
00330     view_type remoteLIDs      = exporter.getExportLIDs();
00331     view_type permuteToLIDs   = exporter.getPermuteFromLIDs();
00332     view_type permuteFromLIDs = exporter.getPermuteToLIDs();
00333     doTransfer (source, CM, numSameIDs, permuteToLIDs, permuteFromLIDs, remoteLIDs,
00334                 exportLIDs, exporter.getDistributor (), DoReverse);
00335   }
00336 
00337   template <class Packet, class LocalOrdinal, class GlobalOrdinal, class Device>
00338   void
00339   DistObject<Packet,LocalOrdinal,GlobalOrdinal,Kokkos::Compat::KokkosDeviceWrapperNode<Device> >::
00340   doExport (const SrcDistObject& source,
00341             const Import<LocalOrdinal,GlobalOrdinal,Node> & importer,
00342             CombineMode CM)
00343   {
00344     TEUCHOS_TEST_FOR_EXCEPTION(
00345       *getMap() != *importer.getSourceMap(), std::invalid_argument,
00346       "doExport (reverse mode): The target object's Map "
00347       "is not identical to the Import's source Map.");
00348 #ifdef HAVE_TPETRA_DEBUG
00349     {
00350       typedef DistObject<Packet,LocalOrdinal,GlobalOrdinal,Node> this_type;
00351       const this_type* srcDistObj = dynamic_cast<const this_type*> (&source);
00352       TEUCHOS_TEST_FOR_EXCEPTION(
00353         srcDistObj != NULL && * (srcDistObj->getMap ()) != *importer.getTargetMap(),
00354         std::invalid_argument,
00355         "doExport (reverse mode): The source is a DistObject, yet its "
00356         "Map is not identical to the Import's target Map.");
00357     }
00358 #endif // HAVE_TPETRA_DEBUG
00359     size_t numSameIDs = importer.getNumSameIDs();
00360 
00361     typedef ArrayView<const LocalOrdinal> view_type;
00362     view_type exportLIDs      = importer.getRemoteLIDs();
00363     view_type remoteLIDs      = importer.getExportLIDs();
00364     view_type permuteToLIDs   = importer.getPermuteFromLIDs();
00365     view_type permuteFromLIDs = importer.getPermuteToLIDs();
00366     doTransfer (source, CM, numSameIDs, permuteToLIDs, permuteFromLIDs, remoteLIDs,
00367                 exportLIDs, importer.getDistributor (), DoReverse);
00368   }
00369 
00370   template <class Packet, class LocalOrdinal, class GlobalOrdinal, class Device>
00371   bool
00372   DistObject<Packet,LocalOrdinal,GlobalOrdinal,Kokkos::Compat::KokkosDeviceWrapperNode<Device> >::isDistributed() const {
00373     return map_->isDistributed ();
00374   }
00375 
00376   template <class Packet, class LocalOrdinal, class GlobalOrdinal, class Device>
00377   size_t
00378   DistObject<Packet,LocalOrdinal,GlobalOrdinal,Kokkos::Compat::KokkosDeviceWrapperNode<Device> >::
00379   constantNumberOfPackets () const {
00380     return 0; // default implementation; subclasses may override
00381   }
00382 
00383   template <class Packet, class LocalOrdinal, class GlobalOrdinal, class Device>
00384   void
00385   DistObject<Packet,LocalOrdinal,GlobalOrdinal,Kokkos::Compat::KokkosDeviceWrapperNode<Device> >::
00386   doTransfer (const SrcDistObject& src,
00387               CombineMode CM,
00388               size_t numSameIDs,
00389               const Teuchos::ArrayView<const LocalOrdinal>& permuteToLIDs_,
00390               const Teuchos::ArrayView<const LocalOrdinal>& permuteFromLIDs_,
00391               const Teuchos::ArrayView<const LocalOrdinal>& remoteLIDs_,
00392               const Teuchos::ArrayView<const LocalOrdinal>& exportLIDs_,
00393               Distributor &distor,
00394               ReverseOption revOp)
00395   {
00396     if (this->useNewInterface()) {
00397       doTransferNew(src, CM, numSameIDs, permuteToLIDs_, permuteFromLIDs_, remoteLIDs_, exportLIDs_, distor, revOp);
00398     }
00399     else {
00400       doTransferOld(src, CM, numSameIDs, permuteToLIDs_, permuteFromLIDs_, remoteLIDs_, exportLIDs_, distor, revOp);
00401     }
00402   }
00403 
00404   template <class Packet, class LocalOrdinal, class GlobalOrdinal, class Device>
00405   void
00406   DistObject<Packet,LocalOrdinal,GlobalOrdinal,Kokkos::Compat::KokkosDeviceWrapperNode<Device> >::
00407   doTransferOld (const SrcDistObject& src,
00408               CombineMode CM,
00409               size_t numSameIDs,
00410               const Teuchos::ArrayView<const LocalOrdinal>& permuteToLIDs,
00411               const Teuchos::ArrayView<const LocalOrdinal>& permuteFromLIDs,
00412               const Teuchos::ArrayView<const LocalOrdinal>& remoteLIDs,
00413               const Teuchos::ArrayView<const LocalOrdinal>& exportLIDs,
00414               Distributor &distor,
00415               ReverseOption revOp)
00416   {
00417     using Teuchos::as;
00418 #ifdef HAVE_TPETRA_TRANSFER_TIMERS
00419     Teuchos::TimeMonitor doXferMon (*doXferTimer_);
00420 #endif // HAVE_TPETRA_TRANSFER_TIMERS
00421 
00422     TEUCHOS_TEST_FOR_EXCEPTION(
00423       ! checkSizes (src), std::invalid_argument,
00424       "Tpetra::DistObject::doTransfer(): checkSizes() indicates that the "
00425       "destination object is not a legal target for redistribution from the "
00426       "source object.  This probably means that they do not have the same "
00427       "dimensions.  For example, MultiVectors must have the same number of "
00428       "rows and columns.");
00429     KokkosClassic::ReadWriteOption rwo = KokkosClassic::ReadWrite;
00430     if (CM == INSERT || CM == REPLACE) {
00431       const size_t numIDsToWrite = numSameIDs +
00432         as<size_t> (permuteToLIDs.size ()) +
00433         as<size_t> (remoteLIDs.size ());
00434       if (numIDsToWrite == this->getMap ()->getNodeNumElements ()) {
00435         // We're overwriting all of our local data in the destination
00436         // object, so a write-only view suffices.
00437         //
00438         // FIXME (mfh 10 Apr 2012) This doesn't make sense for a
00439         // CrsMatrix with a dynamic graph.  INSERT mode could mean
00440         // that we're adding new entries to the object, but we don't
00441         // want to get rid of the old ones.
00442         rwo = KokkosClassic::WriteOnly;
00443       }
00444     }
00445     // Tell the source to create a read-only view of its data.  On a
00446     // discrete accelerator such as a GPU, this brings EVERYTHING from
00447     // device memory to host memory.
00448     //
00449     // FIXME (mfh 23 Mar 2012) By passing in the list of GIDs (or
00450     // rather, local LIDs to send) and packet counts, createViews()
00451     // could create a "sparse view" that only brings in the necessary
00452     // data from device to host memory.
00453     typedef DistObject<Packet,LocalOrdinal,GlobalOrdinal,Node> this_type;
00454     const this_type* srcDistObj = dynamic_cast<const this_type*> (&src);
00455     if (srcDistObj != NULL) {
00456       srcDistObj->createViews ();
00457     }
00458 
00459     // Tell the target to create a view of its data.  Depending on
00460     // rwo, this could be a write-only view or a read-and-write view.
00461     // On a discrete accelerator such as a GPU, a write-only view only
00462     // requires a transfer from host to device memory.  A
00463     // read-and-write view requires a two-way transfer.  This has the
00464     // same problem as createViews(): it transfers EVERYTHING, not
00465     // just the necessary data.
00466     //
00467     // FIXME (mfh 23 Mar 2012) By passing in the list of GIDs (or
00468     // rather, local LIDs into which to receive) and packet counts,
00469     // createViewsNonConst() could create a "sparse view" that only
00470     // transfers the necessary data.
00471     this->createViewsNonConst (rwo);
00472 
00473     if (numSameIDs + permuteToLIDs.size()) {
00474 #ifdef HAVE_TPETRA_TRANSFER_TIMERS
00475       Teuchos::TimeMonitor copyAndPermuteMon (*copyAndPermuteTimer_);
00476 #endif // HAVE_TPETRA_TRANSFER_TIMERS
00477       // There is at least one GID to copy or permute.
00478       copyAndPermute (src, numSameIDs, permuteToLIDs, permuteFromLIDs);
00479     }
00480 
00481     // The method may return zero even if the implementation actually
00482     // does have a constant number of packets per LID.  However, if it
00483     // returns nonzero, we may use this information to avoid
00484     // (re)allocating num{Ex,Im}portPacketsPerLID_.  packAndPrepare()
00485     // will set this to its final value.
00486     //
00487     // We only need this if CM != ZERO, but it has to be lifted out of
00488     // that scope because there are multiple tests for CM != ZERO.
00489     size_t constantNumPackets = this->constantNumberOfPackets ();
00490 
00491     // We only need to pack communication buffers if the combine mode
00492     // is not ZERO. A "ZERO combine mode" means that the results are
00493     // the same as if we had received all zeros, and added them to the
00494     // existing values. That means we don't need to communicate.
00495     if (CM != ZERO) {
00496       if (constantNumPackets == 0) {
00497         numExportPacketsPerLID_old_.resize (exportLIDs.size ());
00498         numImportPacketsPerLID_old_.resize (remoteLIDs.size ());
00499       }
00500 
00501       {
00502 #ifdef HAVE_TPETRA_TRANSFER_TIMERS
00503         Teuchos::TimeMonitor packAndPrepareMon (*packAndPrepareTimer_);
00504 #endif // HAVE_TPETRA_TRANSFER_TIMERS
00505         // Ask the source to pack data.  Also ask it whether there are a
00506         // constant number of packets per element (constantNumPackets is
00507         // an output argument).  If there are, constantNumPackets will
00508         // come back nonzero.  Otherwise, the source will fill the
00509         // numExportPacketsPerLID_ array.
00510         packAndPrepare (src, exportLIDs, exports_old_, numExportPacketsPerLID_old_ (),
00511                         constantNumPackets, distor);
00512       }
00513     }
00514 
00515     // We don't need the source's data anymore, so it can let go of
00516     // its views.  On an accelerator device with a separate memory
00517     // space (like a GPU), this frees host memory, since device memory
00518     // has the "master" version of the data.
00519     if (srcDistObj != NULL) {
00520       srcDistObj->releaseViews ();
00521     }
00522 
00523     // We only need to send data if the combine mode is not ZERO.
00524     if (CM != ZERO) {
00525       if (constantNumPackets != 0) {
00526         // There are a constant number of packets per element.  We
00527         // already know (from the number of "remote" (incoming)
00528         // elements) how many incoming elements we expect, so we can
00529         // resize the buffer accordingly.
00530         const size_t rbufLen = remoteLIDs.size() * constantNumPackets;
00531         if (as<size_t> (imports_old_.size()) != rbufLen) {
00532           imports_old_.resize (rbufLen);
00533         }
00534       }
00535 
00536       // Do we need to do communication (via doPostsAndWaits)?
00537       bool needCommunication = true;
00538       if (revOp == DoReverse && ! isDistributed ()) {
00539         needCommunication = false;
00540       }
00541       // FIXME (mfh 30 Jun 2013): Checking whether the source object
00542       // is distributed requires a cast to DistObject.  If it's not a
00543       // DistObject, then I'm not quite sure what to do.  Perhaps it
00544       // would be more appropriate for SrcDistObject to have an
00545       // isDistributed() method.  For now, I'll just assume that we
00546       // need to do communication unless the cast succeeds and the
00547       // source is not distributed.
00548       else if (revOp == DoForward && srcDistObj != NULL &&
00549                ! srcDistObj->isDistributed ()) {
00550         needCommunication = false;
00551       }
00552 
00553       if (needCommunication) {
00554         if (revOp == DoReverse) {
00555 #ifdef HAVE_TPETRA_TRANSFER_TIMERS
00556           Teuchos::TimeMonitor doPostsAndWaitsMon (*doPostsAndWaitsTimer_);
00557 #endif // HAVE_TPETRA_TRANSFER_TIMERS
00558           if (constantNumPackets == 0) { //variable num-packets-per-LID:
00559             distor.doReversePostsAndWaits (numExportPacketsPerLID_old_().getConst(),
00560                                            1,
00561                                            numImportPacketsPerLID_old_());
00562             size_t totalImportPackets = 0;
00563             for (Array_size_type i = 0; i < numImportPacketsPerLID_old_.size(); ++i) {
00564               totalImportPackets += numImportPacketsPerLID_old_[i];
00565             }
00566             imports_old_.resize(totalImportPackets);
00567             distor.doReversePostsAndWaits (exports_old_().getConst(),
00568                                            numExportPacketsPerLID_old_(),
00569                                            imports_old_(),
00570                                            numImportPacketsPerLID_old_());
00571           }
00572           else {
00573             distor.doReversePostsAndWaits (exports_old_ ().getConst (),
00574                                            constantNumPackets,
00575                                            imports_old_ ());
00576           }
00577         }
00578         else { // revOp == DoForward
00579 #ifdef HAVE_TPETRA_TRANSFER_TIMERS
00580           Teuchos::TimeMonitor doPostsAndWaitsMon (*doPostsAndWaitsTimer_);
00581 #endif // HAVE_TPETRA_TRANSFER_TIMERS
00582           if (constantNumPackets == 0) { //variable num-packets-per-LID:
00583             distor.doPostsAndWaits (numExportPacketsPerLID_old_().getConst(), 1,
00584                                     numImportPacketsPerLID_old_());
00585             size_t totalImportPackets = 0;
00586             for (Array_size_type i = 0; i < numImportPacketsPerLID_old_.size(); ++i) {
00587               totalImportPackets += numImportPacketsPerLID_old_[i];
00588             }
00589             imports_old_.resize(totalImportPackets);
00590             distor.doPostsAndWaits (exports_old_().getConst(),
00591                                     numExportPacketsPerLID_old_(),
00592                                     imports_old_(),
00593                                     numImportPacketsPerLID_old_());
00594           }
00595           else {
00596             distor.doPostsAndWaits (exports_old_ ().getConst (),
00597                                     constantNumPackets,
00598                                     imports_old_ ());
00599           }
00600         }
00601         {
00602 #ifdef HAVE_TPETRA_TRANSFER_TIMERS
00603           Teuchos::TimeMonitor unpackAndCombineMon (*unpackAndCombineTimer_);
00604 #endif // HAVE_TPETRA_TRANSFER_TIMERS
00605           unpackAndCombine (remoteLIDs, imports_old_(), numImportPacketsPerLID_old_(),
00606                             constantNumPackets, distor, CM);
00607         }
00608       }
00609     } // if (CM != ZERO)
00610 
00611     this->releaseViews ();
00612   }
00613 
00614   template <class Packet, class LocalOrdinal, class GlobalOrdinal, class Device>
00615   void
00616   DistObject<Packet,LocalOrdinal,GlobalOrdinal,Kokkos::Compat::KokkosDeviceWrapperNode<Device> >::
00617   doTransferNew (const SrcDistObject& src,
00618               CombineMode CM,
00619               size_t numSameIDs,
00620               const Teuchos::ArrayView<const LocalOrdinal>& permuteToLIDs_,
00621               const Teuchos::ArrayView<const LocalOrdinal>& permuteFromLIDs_,
00622               const Teuchos::ArrayView<const LocalOrdinal>& remoteLIDs_,
00623               const Teuchos::ArrayView<const LocalOrdinal>& exportLIDs_,
00624               Distributor &distor,
00625               ReverseOption revOp)
00626   {
00627     using Teuchos::as;
00628     using Kokkos::Compat::getArrayView;
00629     using Kokkos::Compat::getConstArrayView;
00630     using Kokkos::Compat::getKokkosViewDeepCopy;
00631     using Kokkos::Compat::create_const_view;
00632 
00633 #ifdef HAVE_TPETRA_TRANSFER_TIMERS
00634     Teuchos::TimeMonitor doXferMon (*doXferTimer_);
00635 #endif // HAVE_TPETRA_TRANSFER_TIMERS
00636 
00637     // Convert arguments to Kokkos::View's (involves deep copy to device)
00638     //
00639     // FIXME (mfh 17 Feb 2014) getKokkosViewDeepCopy _always_ does a
00640     // deep copy.  It has to, since it returns a managed Kokkos::View,
00641     // but the input Teuchos::ArrayView is unmanaged.  One way to fix
00642     // this would be to change the interface by replacing the
00643     // Teuchos::ArrayView inputs with Kokkos::View inputs.  This is
00644     // the approach taken by Kokkos::DistObjectKA.  Some points:
00645     //
00646     //   1. It's perfectly OK to change the interface of doTransfer.
00647     //      It should take Kokkos::View by default, and convert to
00648     //      Teuchos::Array{RCP,View} if needed internally.
00649     //   2. Recall that Teuchos::ArrayView is an unmanaged view.
00650     //   3. If DistObject ever gets a nonblocking interface, that
00651     //      interface should take managed views.
00652     typedef Kokkos::View<const LocalOrdinal*, device_type> lo_const_view_type;
00653     lo_const_view_type permuteToLIDs =
00654       getKokkosViewDeepCopy<device_type> (permuteToLIDs_);
00655     lo_const_view_type permuteFromLIDs =
00656       getKokkosViewDeepCopy<device_type> (permuteFromLIDs_);
00657     lo_const_view_type remoteLIDs =
00658       getKokkosViewDeepCopy<device_type> (remoteLIDs_);
00659     lo_const_view_type exportLIDs =
00660       getKokkosViewDeepCopy<device_type> (exportLIDs_);
00661 
00662     TEUCHOS_TEST_FOR_EXCEPTION(
00663       ! checkSizes (src), std::invalid_argument,
00664       "Tpetra::DistObject::doTransfer(): checkSizes() indicates that the "
00665       "destination object is not a legal target for redistribution from the "
00666       "source object.  This probably means that they do not have the same "
00667       "dimensions.  For example, MultiVectors must have the same number of "
00668       "rows and columns.");
00669     KokkosClassic::ReadWriteOption rwo = KokkosClassic::ReadWrite;
00670     if (CM == INSERT || CM == REPLACE) {
00671       const size_t numIDsToWrite = numSameIDs +
00672         as<size_t> (permuteToLIDs.size ()) +
00673         as<size_t> (remoteLIDs.size ());
00674       if (numIDsToWrite == this->getMap ()->getNodeNumElements ()) {
00675         // We're overwriting all of our local data in the destination
00676         // object, so a write-only view suffices.
00677         //
00678         // FIXME (mfh 10 Apr 2012) This doesn't make sense for a
00679         // CrsMatrix with a dynamic graph.  INSERT mode could mean
00680         // that we're adding new entries to the object, but we don't
00681         // want to get rid of the old ones.
00682         rwo = KokkosClassic::WriteOnly;
00683       }
00684     }
00685 
00686     // FIXME (mfh 17 Feb 2014) We're assuming that MPI can read device
00687     // memory (that's even pre-UVM), so there is no need to create
00688     // host views of the source object's data.
00689 
00690     // Tell the source to create a read-only view of its data.  On a
00691     // discrete accelerator such as a GPU, this brings EVERYTHING from
00692     // device memory to host memory.
00693     //
00694     // FIXME (mfh 23 Mar 2012) By passing in the list of GIDs (or
00695     // rather, local LIDs to send) and packet counts, createViews()
00696     // could create a "sparse view" that only brings in the necessary
00697     // data from device to host memory.
00698     typedef DistObject<Packet,LocalOrdinal,GlobalOrdinal,Node> this_type;
00699     const this_type* srcDistObj = dynamic_cast<const this_type*> (&src);
00700     if (srcDistObj != NULL) {
00701       srcDistObj->createViews ();
00702     }
00703 
00704     // FIXME (mfh 17 Feb 2014) We're assuming that MPI can read device
00705     // memory (that's even pre-UVM), so there is no need to create
00706     // host views of the target object's data.
00707 
00708     // Tell the target to create a view of its data.  Depending on
00709     // rwo, this could be a write-only view or a read-and-write view.
00710     // On a discrete accelerator such as a GPU, a write-only view only
00711     // requires a transfer from host to device memory.  A
00712     // read-and-write view requires a two-way transfer.  This has the
00713     // same problem as createViews(): it transfers EVERYTHING, not
00714     // just the necessary data.
00715     //
00716     // FIXME (mfh 23 Mar 2012) By passing in the list of GIDs (or
00717     // rather, local LIDs into which to receive) and packet counts,
00718     // createViewsNonConst() could create a "sparse view" that only
00719     // transfers the necessary data.
00720     this->createViewsNonConst (rwo);
00721 
00722     if (numSameIDs + permuteToLIDs.size()) {
00723 #ifdef HAVE_TPETRA_TRANSFER_TIMERS
00724       Teuchos::TimeMonitor copyAndPermuteMon (*copyAndPermuteTimer_);
00725 #endif // HAVE_TPETRA_TRANSFER_TIMERS
00726 
00727       // FIXME (mfh 17 Feb 2014) Nobody implements DistObject
00728       // subclasses but Tpetra developers anyway, so don't bother with
00729       // this "new" business.  Just write the interface you want.
00730 
00731       // There is at least one GID to copy or permute.
00732       copyAndPermuteNew (src, numSameIDs, permuteToLIDs, permuteFromLIDs);
00733     }
00734 
00735     // The method may return zero even if the implementation actually
00736     // does have a constant number of packets per LID.  However, if it
00737     // returns nonzero, we may use this information to avoid
00738     // (re)allocating num{Ex,Im}portPacketsPerLID_.  packAndPrepare()
00739     // will set this to its final value.
00740     //
00741     // We only need this if CM != ZERO, but it has to be lifted out of
00742     // that scope because there are multiple tests for CM != ZERO.
00743     size_t constantNumPackets = this->constantNumberOfPackets ();
00744 
00745     // We only need to pack communication buffers if the combine mode
00746     // is not ZERO. A "ZERO combine mode" means that the results are
00747     // the same as if we had received all zeros, and added them to the
00748     // existing values. That means we don't need to communicate.
00749     if (CM != ZERO) {
00750       if (constantNumPackets == 0) {
00751         // FIXME (mfh 17 Feb 2014) Don't "realloc" unless you really
00752         // need to.  That will avoid a bit of time for reinitializing
00753         // the Views' data.
00754         Kokkos::Compat::realloc (numExportPacketsPerLID_, exportLIDs.size ());
00755         Kokkos::Compat::realloc (numImportPacketsPerLID_, remoteLIDs.size ());
00756       }
00757 
00758       {
00759 #ifdef HAVE_TPETRA_TRANSFER_TIMERS
00760         Teuchos::TimeMonitor packAndPrepareMon (*packAndPrepareTimer_);
00761 #endif // HAVE_TPETRA_TRANSFER_TIMERS
00762         // Ask the source to pack data.  Also ask it whether there are a
00763         // constant number of packets per element (constantNumPackets is
00764         // an output argument).  If there are, constantNumPackets will
00765         // come back nonzero.  Otherwise, the source will fill the
00766         // numExportPacketsPerLID_ array.
00767         packAndPrepareNew (src, exportLIDs, exports_, numExportPacketsPerLID_,
00768                         constantNumPackets, distor);
00769       }
00770     }
00771 
00772     // FIXME (mfh 17 Feb 2014) See comments above; there is no need to
00773     // create host views of the source object's data.
00774 
00775     // We don't need the source's data anymore, so it can let go of
00776     // its views.  On an accelerator device with a separate memory
00777     // space (like a GPU), this frees host memory, since device memory
00778     // has the "master" version of the data.
00779     if (srcDistObj != NULL) {
00780       srcDistObj->releaseViews ();
00781     }
00782 
00783     // We only need to send data if the combine mode is not ZERO.
00784     if (CM != ZERO) {
00785       if (constantNumPackets != 0) {
00786         // There are a constant number of packets per element.  We
00787         // already know (from the number of "remote" (incoming)
00788         // elements) how many incoming elements we expect, so we can
00789         // resize the buffer accordingly.
00790         const size_t rbufLen = remoteLIDs.size() * constantNumPackets;
00791         if (as<size_t> (imports_.size()) != rbufLen) {
00792           Kokkos::Compat::realloc (imports_, rbufLen);
00793         }
00794       }
00795 
00796       // FIXME (mfh 17 Feb 2014) Why do we need to create mirror
00797       // views?  Furthermore, if we do need to do this, we should only
00798       // do it _once_, since the arrays are constant (they come from
00799       // the Import / Export object, which is constant).
00800 
00801       // Create mirror views of [import|export]PacketsPerLID
00802       typename Kokkos::View<size_t*,device_type>::HostMirror host_numExportPacketsPerLID = Kokkos::create_mirror_view (numExportPacketsPerLID_);
00803       typename Kokkos::View<size_t*,device_type>::HostMirror host_numImportPacketsPerLID = Kokkos::create_mirror_view (numImportPacketsPerLID_);
00804 
00805       // Copy numExportPacketsPerLID to host
00806       Kokkos::deep_copy (host_numExportPacketsPerLID, numExportPacketsPerLID_);
00807 
00808       // Do we need to do communication (via doPostsAndWaits)?
00809       bool needCommunication = true;
00810       if (revOp == DoReverse && ! isDistributed ()) {
00811         needCommunication = false;
00812       }
00813       // FIXME (mfh 30 Jun 2013): Checking whether the source object
00814       // is distributed requires a cast to DistObject.  If it's not a
00815       // DistObject, then I'm not quite sure what to do.  Perhaps it
00816       // would be more appropriate for SrcDistObject to have an
00817       // isDistributed() method.  For now, I'll just assume that we
00818       // need to do communication unless the cast succeeds and the
00819       // source is not distributed.
00820       else if (revOp == DoForward && srcDistObj != NULL &&
00821                ! srcDistObj->isDistributed ()) {
00822         needCommunication = false;
00823       }
00824 
00825       // FIXME (mfh 17 Feb 2014) Distributor doesn't actually inspect
00826       // the contents of the "exports" or "imports" arrays, other than
00827       // to do a deep copy in the (should be technically unnecessary,
00828       // but isn't for some odd reason) "self-message" case.
00829       // Distributor thus doesn't need host views; it could do just
00830       // fine with device views, assuming that MPI knows how to read
00831       // device memory (which doesn't even require UVM).
00832 
00833       if (needCommunication) {
00834         if (revOp == DoReverse) {
00835 #ifdef HAVE_TPETRA_TRANSFER_TIMERS
00836           Teuchos::TimeMonitor doPostsAndWaitsMon (*doPostsAndWaitsTimer_);
00837 #endif // HAVE_TPETRA_TRANSFER_TIMERS
00838           if (constantNumPackets == 0) { //variable num-packets-per-LID:
00839             distor.doReversePostsAndWaits (create_const_view (host_numExportPacketsPerLID),
00840                                            1,
00841                                            host_numImportPacketsPerLID);
00842             size_t totalImportPackets = 0;
00843             // FIXME (mfh 17 Feb 2014) This would be a good place for
00844             // a Kokkos reduction.  numImportPacketsPerLID_ has as
00845             // many entries as the number of LIDs on the calling
00846             // process.
00847             for (view_size_type i = 0; i < numImportPacketsPerLID_.size(); ++i) {
00848               totalImportPackets += host_numImportPacketsPerLID[i];
00849             }
00850             // FIXME (mfh 17 Feb 2014) Only realloc if necessary.
00851             Kokkos::Compat::realloc (imports_, totalImportPackets);
00852             distor.doReversePostsAndWaits (create_const_view (exports_),
00853                                            getArrayView (host_numExportPacketsPerLID),
00854                                            imports_,
00855                                            getArrayView (host_numImportPacketsPerLID));
00856           }
00857           else {
00858             distor.doReversePostsAndWaits (create_const_view (exports_),
00859                                            constantNumPackets,
00860                                            imports_);
00861           }
00862         }
00863         else { // revOp == DoForward
00864 #ifdef HAVE_TPETRA_TRANSFER_TIMERS
00865           Teuchos::TimeMonitor doPostsAndWaitsMon (*doPostsAndWaitsTimer_);
00866 #endif // HAVE_TPETRA_TRANSFER_TIMERS
00867           if (constantNumPackets == 0) { //variable num-packets-per-LID:
00868             distor.doPostsAndWaits (create_const_view (host_numExportPacketsPerLID), 1,
00869                                     host_numImportPacketsPerLID);
00870             size_t totalImportPackets = 0;
00871             // FIXME (mfh 17 Feb 2014) This would be a good place for
00872             // a Kokkos reduction.  numImportPacketsPerLID_ has as
00873             // many entries as the number of LIDs on the calling
00874             // process.
00875             for (view_size_type i = 0; i < numImportPacketsPerLID_.size(); ++i) {
00876               totalImportPackets += host_numImportPacketsPerLID[i];
00877             }
00878             // FIXME (mfh 17 Feb 2014) Only realloc if necessary.
00879             Kokkos::Compat::realloc (imports_, totalImportPackets);
00880             distor.doPostsAndWaits (create_const_view (exports_),
00881                                     getArrayView (host_numExportPacketsPerLID),
00882                                     imports_,
00883                                     getArrayView (host_numImportPacketsPerLID));
00884           }
00885           else {
00886             distor.doPostsAndWaits (create_const_view (exports_),
00887                                     constantNumPackets,
00888                                     imports_);
00889           }
00890         }
00891 
00892         // FIXME (mfh 17 Feb 2014) This array should just live on the
00893         // device and stay there.  There is no need for a host view,
00894         // as long as unpackAndCombine(new) knows what to do with a
00895         // device view.
00896         //
00897         // Copy numImportPacketsPerLID to device
00898         Kokkos::deep_copy (numImportPacketsPerLID_, host_numImportPacketsPerLID);
00899 
00900         {
00901 #ifdef HAVE_TPETRA_TRANSFER_TIMERS
00902           Teuchos::TimeMonitor unpackAndCombineMon (*unpackAndCombineTimer_);
00903 #endif // HAVE_TPETRA_TRANSFER_TIMERS
00904           unpackAndCombineNew (remoteLIDs, imports_, numImportPacketsPerLID_,
00905                             constantNumPackets, distor, CM);
00906         }
00907       }
00908     } // if (CM != ZERO)
00909 
00910     // FIXME (mfh 17 Dec 2014) We don't have to call releaseViews() on
00911     // the destination object any more, since MPI knows how to read
00912     // device memory.
00913 
00914     this->releaseViews ();
00915   }
00916 
00917   template <class Packet, class LocalOrdinal, class GlobalOrdinal, class Device>
00918   void
00919   DistObject<Packet,LocalOrdinal,GlobalOrdinal,Kokkos::Compat::KokkosDeviceWrapperNode<Device> >::print (std::ostream &os) const
00920   {
00921     using Teuchos::FancyOStream;
00922     using Teuchos::getFancyOStream;
00923     using Teuchos::RCP;
00924     using Teuchos::rcpFromRef;
00925     using std::endl;
00926 
00927     RCP<FancyOStream> out = getFancyOStream (rcpFromRef (os));
00928     this->describe (*out, Teuchos::VERB_DEFAULT);
00929   }
00930 
00931   template <class Packet, class LocalOrdinal, class GlobalOrdinal, class Device>
00932   void
00933   DistObject<Packet,LocalOrdinal,GlobalOrdinal,Kokkos::Compat::KokkosDeviceWrapperNode<Device> >::createViews () const
00934   {}
00935 
00936   template <class Packet, class LocalOrdinal, class GlobalOrdinal, class Device>
00937   void
00938   DistObject<Packet,LocalOrdinal,GlobalOrdinal,Kokkos::Compat::KokkosDeviceWrapperNode<Device> >::
00939   createViewsNonConst (KokkosClassic::ReadWriteOption /*rwo*/)
00940   {}
00941 
00942   template <class Packet, class LocalOrdinal, class GlobalOrdinal, class Device>
00943   void
00944   DistObject<Packet,LocalOrdinal,GlobalOrdinal,Kokkos::Compat::KokkosDeviceWrapperNode<Device> >::
00945   releaseViews () const
00946   {}
00947 
00948 /* These are provided in base DistObject template
00949 #define TPETRA_DISTOBJECT_INSTANT(SCALAR, LO, GO, NODE) \
00950   \
00951   template class DistObject< SCALAR , LO , GO , NODE >;
00952 
00953  // The "SLGN" stuff above doesn't work for Packet=char.
00954 #define TPETRA_DISTOBJECT_INSTANT_CHAR(LO, GO, NODE) \
00955   \
00956   template class DistObject< char , LO , GO , NODE >;
00957 */
00958 
00959 } // namespace Tpetra
00960 
00961 #endif /* TPETRA_DISTOBJECT_DEF_HPP */
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines