|
Tpetra Matrix/Vector Services
Version of the Day
|
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 */
1.7.6.1