|
Anasazi
Version of the Day
|
00001 // @HEADER 00002 // *********************************************************************** 00003 // 00004 // Anasazi: Block Eigensolvers Package 00005 // Copyright (2004) Sandia Corporation 00006 // 00007 // Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive 00008 // license for use of this work by or on behalf of the U.S. Government. 00009 // 00010 // This library is free software; you can redistribute it and/or modify 00011 // it under the terms of the GNU Lesser General Public License as 00012 // published by the Free Software Foundation; either version 2.1 of the 00013 // License, or (at your option) any later version. 00014 // 00015 // This library is distributed in the hope that it will be useful, but 00016 // WITHOUT ANY WARRANTY; without even the implied warranty of 00017 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00018 // Lesser General Public License for more details. 00019 // 00020 // You should have received a copy of the GNU Lesser General Public 00021 // License along with this library; if not, write to the Free Software 00022 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 00023 // USA 00024 // Questions? Contact Michael A. Heroux (maherou@sandia.gov) 00025 // 00026 // *********************************************************************** 00027 // @HEADER 00028 00029 #ifndef ANASAZI_TPETRA_ADAPTER_HPP 00030 #define ANASAZI_TPETRA_ADAPTER_HPP 00031 00068 00069 #include <Tpetra_MultiVector.hpp> 00070 #include <Tpetra_Operator.hpp> 00071 00072 #include <Teuchos_Array.hpp> 00073 #include <Teuchos_Assert.hpp> 00074 #include <Teuchos_DefaultSerialComm.hpp> 00075 #include <Teuchos_ScalarTraits.hpp> 00076 00077 #include <AnasaziConfigDefs.hpp> 00078 #include <AnasaziTypes.hpp> 00079 #include <AnasaziMultiVecTraits.hpp> 00080 #include <AnasaziOperatorTraits.hpp> 00081 00082 #ifdef HAVE_ANASAZI_TSQR 00083 # include <Tpetra_TsqrAdaptor.hpp> 00084 #endif // HAVE_ANASAZI_TSQR 00085 00086 00087 namespace Anasazi { 00088 00100 template<class Scalar, class LO, class GO, class Node> 00101 class MultiVecTraits<Scalar, Tpetra::MultiVector<Scalar,LO,GO,Node> > { 00102 typedef Tpetra::MultiVector<Scalar, LO, GO, Node> MV; 00103 public: 00109 static Teuchos::RCP<MV> Clone (const MV& X, const int numVecs) { 00110 Teuchos::RCP<MV> Y (new MV (X.getMap (), numVecs, false)); 00111 Y->setCopyOrView (Teuchos::View); 00112 return Y; 00113 } 00114 00116 static Teuchos::RCP<MV> CloneCopy (const MV& X) 00117 { 00118 // Make a deep copy of X. The one-argument copy constructor 00119 // does a shallow copy by default; the second argument tells it 00120 // to do a deep copy. 00121 Teuchos::RCP<MV> X_copy (new MV (X, Teuchos::Copy)); 00122 // Make Tpetra::MultiVector use the new view semantics. This is 00123 // a no-op for the Kokkos refactor version of Tpetra; it only 00124 // does something for the "classic" version of Tpetra. This 00125 // shouldn't matter because Belos only handles MV through RCP 00126 // and through this interface anyway, but it doesn't hurt to set 00127 // it and make sure that it works. 00128 X_copy->setCopyOrView (Teuchos::View); 00129 return X_copy; 00130 } 00131 00143 static Teuchos::RCP<MV> 00144 CloneCopy (const MV& mv, const std::vector<int>& index) 00145 { 00146 #ifdef HAVE_TPETRA_DEBUG 00147 const char fnName[] = "Anasazi::MultiVecTraits::CloneCopy(mv,index)"; 00148 const size_t inNumVecs = mv.getNumVectors (); 00149 TEUCHOS_TEST_FOR_EXCEPTION( 00150 index.size () > 0 && *std::min_element (index.begin (), index.end ()) < 0, 00151 std::runtime_error, fnName << ": All indices must be nonnegative."); 00152 TEUCHOS_TEST_FOR_EXCEPTION( 00153 index.size () > 0 && 00154 static_cast<size_t> (*std::max_element (index.begin (), index.end ())) >= inNumVecs, 00155 std::runtime_error, 00156 fnName << ": All indices must be strictly less than the number of " 00157 "columns " << inNumVecs << " of the input multivector mv."); 00158 #endif // HAVE_TPETRA_DEBUG 00159 00160 // Tpetra wants an array of size_t, not of int. 00161 Teuchos::Array<size_t> columns (index.size ()); 00162 for (std::vector<int>::size_type j = 0; j < index.size (); ++j) { 00163 columns[j] = index[j]; 00164 } 00165 // mfh 14 Aug 2014: Tpetra already detects and optimizes for a 00166 // continuous column index range in MultiVector::subCopy, so we 00167 // don't have to check here. 00168 Teuchos::RCP<MV> X_copy = mv.subCopy (columns ()); 00169 X_copy->setCopyOrView (Teuchos::View); 00170 return X_copy; 00171 } 00172 00179 static Teuchos::RCP<MV> 00180 CloneCopy (const MV& mv, const Teuchos::Range1D& index) 00181 { 00182 const bool validRange = index.size() > 0 && 00183 index.lbound() >= 0 && 00184 index.ubound() < GetNumberVecs(mv); 00185 if (! validRange) { // invalid range; generate error message 00186 std::ostringstream os; 00187 os << "Anasazi::MultiVecTraits::CloneCopy(mv,index=[" 00188 << index.lbound() << "," << index.ubound() << "]): "; 00189 TEUCHOS_TEST_FOR_EXCEPTION( 00190 index.size() == 0, std::invalid_argument, 00191 os.str() << "Empty index range is not allowed."); 00192 TEUCHOS_TEST_FOR_EXCEPTION( 00193 index.lbound() < 0, std::invalid_argument, 00194 os.str() << "Index range includes negative index/ices, which is not " 00195 "allowed."); 00196 TEUCHOS_TEST_FOR_EXCEPTION( 00197 index.ubound() >= GetNumberVecs(mv), std::invalid_argument, 00198 os.str() << "Index range exceeds number of vectors " 00199 << mv.getNumVectors() << " in the input multivector."); 00200 TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error, 00201 os.str() << "Should never get here!"); 00202 } 00203 Teuchos::RCP<MV> X_copy = mv.subCopy (index); 00204 X_copy->setCopyOrView (Teuchos::View); 00205 return X_copy; 00206 } 00207 00208 static Teuchos::RCP<MV> 00209 CloneViewNonConst (MV& mv, const std::vector<int>& index) 00210 { 00211 #ifdef HAVE_TPETRA_DEBUG 00212 const char fnName[] = "Anasazi::MultiVecTraits::CloneViewNonConst(mv,index)"; 00213 const size_t numVecs = mv.getNumVectors (); 00214 TEUCHOS_TEST_FOR_EXCEPTION( 00215 index.size () > 0 && *std::min_element (index.begin (), index.end ()) < 0, 00216 std::invalid_argument, 00217 fnName << ": All indices must be nonnegative."); 00218 TEUCHOS_TEST_FOR_EXCEPTION( 00219 index.size () > 0 && 00220 static_cast<size_t> (*std::max_element (index.begin (), index.end ())) >= numVecs, 00221 std::invalid_argument, 00222 fnName << ": All indices must be strictly less than the number of " 00223 "columns " << numVecs << " in the input MultiVector mv."); 00224 #endif // HAVE_TPETRA_DEBUG 00225 00226 // Tpetra wants an array of size_t, not of int. 00227 Teuchos::Array<size_t> columns (index.size ()); 00228 for (std::vector<int>::size_type j = 0; j < index.size (); ++j) { 00229 columns[j] = index[j]; 00230 } 00231 // mfh 14 Aug 2014: Tpetra already detects and optimizes for a 00232 // continuous column index range in 00233 // MultiVector::subViewNonConst, so we don't have to check here. 00234 Teuchos::RCP<MV> X_view = mv.subViewNonConst (columns ()); 00235 X_view->setCopyOrView (Teuchos::View); 00236 return X_view; 00237 } 00238 00239 static Teuchos::RCP<MV> 00240 CloneViewNonConst (MV& mv, const Teuchos::Range1D& index) 00241 { 00242 // NOTE (mfh 11 Jan 2011) We really should check for possible 00243 // overflow of int here. However, the number of columns in a 00244 // multivector typically fits in an int. 00245 const int numCols = static_cast<int> (mv.getNumVectors()); 00246 const bool validRange = index.size() > 0 && 00247 index.lbound() >= 0 && index.ubound() < numCols; 00248 if (! validRange) { 00249 std::ostringstream os; 00250 os << "Belos::MultiVecTraits::CloneViewNonConst(mv,index=[" 00251 << index.lbound() << ", " << index.ubound() << "]): "; 00252 TEUCHOS_TEST_FOR_EXCEPTION( 00253 index.size() == 0, std::invalid_argument, 00254 os.str() << "Empty index range is not allowed."); 00255 TEUCHOS_TEST_FOR_EXCEPTION( 00256 index.lbound() < 0, std::invalid_argument, 00257 os.str() << "Index range includes negative inde{x,ices}, which is " 00258 "not allowed."); 00259 TEUCHOS_TEST_FOR_EXCEPTION( 00260 index.ubound() >= numCols, std::invalid_argument, 00261 os.str() << "Index range exceeds number of vectors " << numCols 00262 << " in the input multivector."); 00263 TEUCHOS_TEST_FOR_EXCEPTION( 00264 true, std::logic_error, 00265 os.str() << "Should never get here!"); 00266 } 00267 Teuchos::RCP<MV> X_view = mv.subViewNonConst (index); 00268 X_view->setCopyOrView (Teuchos::View); 00269 return X_view; 00270 } 00271 00272 static Teuchos::RCP<const MV> 00273 CloneView (const MV& mv, const std::vector<int>& index) 00274 { 00275 #ifdef HAVE_TPETRA_DEBUG 00276 const char fnName[] = "Belos::MultiVecTraits<Scalar, " 00277 "Tpetra::MultiVector<...> >::CloneView(mv,index)"; 00278 const size_t numVecs = mv.getNumVectors (); 00279 TEUCHOS_TEST_FOR_EXCEPTION( 00280 *std::min_element (index.begin (), index.end ()) < 0, 00281 std::invalid_argument, 00282 fnName << ": All indices must be nonnegative."); 00283 TEUCHOS_TEST_FOR_EXCEPTION( 00284 static_cast<size_t> (*std::max_element (index.begin (), index.end ())) >= numVecs, 00285 std::invalid_argument, 00286 fnName << ": All indices must be strictly less than the number of " 00287 "columns " << numVecs << " in the input MultiVector mv."); 00288 #endif // HAVE_TPETRA_DEBUG 00289 00290 // Tpetra wants an array of size_t, not of int. 00291 Teuchos::Array<size_t> columns (index.size ()); 00292 for (std::vector<int>::size_type j = 0; j < index.size (); ++j) { 00293 columns[j] = index[j]; 00294 } 00295 // mfh 14 Aug 2014: Tpetra already detects and optimizes for a 00296 // continuous column index range in MultiVector::subView, so we 00297 // don't have to check here. 00298 Teuchos::RCP<const MV> X_view = mv.subView (columns); 00299 Teuchos::rcp_const_cast<MV> (X_view)->setCopyOrView (Teuchos::View); 00300 return X_view; 00301 } 00302 00303 static Teuchos::RCP<const MV> 00304 CloneView (const MV& mv, const Teuchos::Range1D& index) 00305 { 00306 // NOTE (mfh 11 Jan 2011) We really should check for possible 00307 // overflow of int here. However, the number of columns in a 00308 // multivector typically fits in an int. 00309 const int numCols = static_cast<int> (mv.getNumVectors()); 00310 const bool validRange = index.size() > 0 && 00311 index.lbound() >= 0 && index.ubound() < numCols; 00312 if (! validRange) { 00313 std::ostringstream os; 00314 os << "Anasazi::MultiVecTraits::CloneView(mv, index=[" 00315 << index.lbound () << ", " << index.ubound() << "]): "; 00316 TEUCHOS_TEST_FOR_EXCEPTION(index.size() == 0, std::invalid_argument, 00317 os.str() << "Empty index range is not allowed."); 00318 TEUCHOS_TEST_FOR_EXCEPTION(index.lbound() < 0, std::invalid_argument, 00319 os.str() << "Index range includes negative index/ices, which is not " 00320 "allowed."); 00321 TEUCHOS_TEST_FOR_EXCEPTION( 00322 index.ubound() >= numCols, std::invalid_argument, 00323 os.str() << "Index range exceeds number of vectors " << numCols 00324 << " in the input multivector."); 00325 TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error, 00326 os.str() << "Should never get here!"); 00327 } 00328 Teuchos::RCP<const MV> X_view = mv.subView (index); 00329 Teuchos::rcp_const_cast<MV> (X_view)->setCopyOrView (Teuchos::View); 00330 return X_view; 00331 } 00332 00333 static int GetVecLength (const MV& mv) { 00334 return static_cast<int> (mv.getGlobalLength ()); 00335 } 00336 00337 static int GetNumberVecs (const MV& mv) { 00338 return static_cast<int> (mv.getNumVectors ()); 00339 } 00340 00341 static void 00342 MvTimesMatAddMv (Scalar alpha, 00343 const MV& A, 00344 const Teuchos::SerialDenseMatrix<int, Scalar>& B, 00345 Scalar beta, 00346 MV& mv) 00347 { 00348 using Teuchos::ArrayView; 00349 using Teuchos::Comm; 00350 using Teuchos::rcpFromRef; 00351 typedef Tpetra::Map<LO, GO, Node> map_type; 00352 00353 #ifdef HAVE_ANASAZI_TPETRA_TIMERS 00354 const std::string timerName ("Anasazi::MVT::MvTimesMatAddMv"); 00355 Teuchos::RCP<Teuchos::Time> timer = 00356 Teuchos::TimeMonitor::lookupCounter (timerName); 00357 if (timer.is_null ()) { 00358 timer = Teuchos::TimeMonitor::getNewCounter (timerName); 00359 } 00360 TEUCHOS_TEST_FOR_EXCEPTION( 00361 timer.is_null (), std::logic_error, 00362 "Anasazi::MultiVecTraits::MvTimesMatAddMv: " 00363 "Failed to look up timer \"" << timerName << "\". " 00364 "Please report this bug to the Belos developers."); 00365 00366 // This starts the timer. It will be stopped on scope exit. 00367 Teuchos::TimeMonitor timeMon (*timer); 00368 #endif 00369 00370 // Check if B is 1-by-1, in which case we can just call update() 00371 if (B.numRows () == 1 && B.numCols () == 1) { 00372 mv.update (alpha*B(0,0), A, beta); 00373 return; 00374 } 00375 00376 // Create local map 00377 Teuchos::SerialComm<int> serialComm; 00378 map_type LocalMap (B.numRows (), A.getMap ()->getIndexBase (), 00379 rcpFromRef<const Comm<int> > (serialComm), 00380 Tpetra::LocallyReplicated, A.getMap ()->getNode ()); 00381 // encapsulate Teuchos::SerialDenseMatrix data in ArrayView 00382 ArrayView<const Scalar> Bvalues (B.values (), B.stride () * B.numCols ()); 00383 // create locally replicated MultiVector with a copy of this data 00384 MV B_mv (rcpFromRef (LocalMap), Bvalues, B.stride (), B.numCols ()); 00385 mv.multiply (Teuchos::NO_TRANS, Teuchos::NO_TRANS, alpha, A, B_mv, beta); 00386 } 00387 00395 static void 00396 MvAddMv (Scalar alpha, 00397 const MV& A, 00398 Scalar beta, 00399 const MV& B, 00400 MV& mv) 00401 { 00402 mv.update (alpha, A, beta, B, Teuchos::ScalarTraits<Scalar>::zero ()); 00403 } 00404 00405 static void MvScale (MV& mv, Scalar alpha) { 00406 mv.scale (alpha); 00407 } 00408 00409 static void MvScale (MV& mv, const std::vector<Scalar>& alphas) { 00410 mv.scale (alphas); 00411 } 00412 00413 static void 00414 MvTransMv (Scalar alpha, 00415 const MV& A, 00416 const MV& B, 00417 Teuchos::SerialDenseMatrix<int,Scalar>& C) 00418 { 00419 using Tpetra::LocallyReplicated; 00420 using Teuchos::Comm; 00421 using Teuchos::RCP; 00422 using Teuchos::rcp; 00423 using Teuchos::REDUCE_SUM; 00424 using Teuchos::reduceAll; 00425 using Teuchos::SerialComm; 00426 using Teuchos::TimeMonitor; 00427 typedef Tpetra::Map<LO,GO,Node> map_type; 00428 00429 #ifdef HAVE_ANASAZI_TPETRA_TIMERS 00430 const std::string timerName ("Anasazi::MVT::MvTransMv"); 00431 RCP<Teuchos::Time> timer = TimeMonitor::lookupCounter (timerName); 00432 if (timer.is_null ()) { 00433 timer = TimeMonitor::getNewCounter (timerName); 00434 } 00435 TEUCHOS_TEST_FOR_EXCEPTION( 00436 timer.is_null (), std::logic_error, "Anasazi::MvTransMv: " 00437 "Failed to look up timer \"" << timerName << "\". " 00438 "Please report this bug to the Belos developers."); 00439 00440 // This starts the timer. It will be stopped on scope exit. 00441 TimeMonitor timeMon (*timer); 00442 #endif // HAVE_ANASAZI_TPETRA_TIMERS 00443 00444 // Form alpha * A^H * B, then copy into the SerialDenseMatrix. 00445 // We will create a multivector C_mv from a a local map. This 00446 // map has a serial comm, the purpose being to short-circuit the 00447 // MultiVector::reduce() call at the end of 00448 // MultiVector::multiply(). Otherwise, the reduced multivector 00449 // data would be copied back to the GPU, only to turn around and 00450 // have to get it back here. This saves us a round trip for 00451 // this data. 00452 const int numRowsC = C.numRows (); 00453 const int numColsC = C.numCols (); 00454 const int strideC = C.stride (); 00455 00456 // Check if numRowsC == numColsC == 1, in which case we can call dot() 00457 if (numRowsC == 1 && numColsC == 1) { 00458 A.dot (B, Teuchos::ArrayView<Scalar> (C.values (), 1)); 00459 return; 00460 } 00461 00462 RCP<Comm<int> > serialComm (new SerialComm<int> ()); 00463 // create local map with serial comm 00464 RCP<const map_type> LocalMap = 00465 rcp (new map_type (numRowsC, 0, serialComm, LocallyReplicated, 00466 A.getMap ()->getNode ())); 00467 // create local multivector to hold the result 00468 const bool INIT_TO_ZERO = true; 00469 MV C_mv (LocalMap, numColsC, INIT_TO_ZERO); 00470 00471 // multiply result into local multivector 00472 C_mv.multiply (Teuchos::CONJ_TRANS, Teuchos::NO_TRANS, alpha, A, B, 00473 Teuchos::ScalarTraits<Scalar>::zero ()); 00474 // get comm 00475 RCP<const Comm<int> > pcomm = A.getMap ()->getComm (); 00476 // create arrayview encapsulating the Teuchos::SerialDenseMatrix 00477 Teuchos::ArrayView<Scalar> C_view (C.values (), strideC * numColsC); 00478 if (pcomm->getSize() == 1) { 00479 // No accumulation to do; simply extract the multivector data 00480 // into C. Extract a copy of the result into the array view 00481 // (and therefore, the SerialDenseMatrix). 00482 C_mv.get1dCopy (C_view, strideC); 00483 } 00484 else { 00485 // get a const host view of the data in C_mv 00486 Teuchos::ArrayRCP<const Scalar> C_mv_view = C_mv.get1dView(); 00487 if (strideC == numRowsC) { 00488 // sum-all into C 00489 reduceAll<int, Scalar> (*pcomm, REDUCE_SUM, numColsC*numRowsC, 00490 C_mv_view.getRawPtr (), C_view.getRawPtr ()); 00491 } 00492 else { 00493 // sum-all into temp, copy into C 00494 Teuchos::Array<Scalar> destBuff (numColsC * numRowsC); 00495 reduceAll<int,Scalar> (*pcomm, REDUCE_SUM, numColsC*numRowsC, 00496 C_mv_view.getRawPtr (), destBuff.getRawPtr ()); 00497 for (int j=0; j < numColsC; ++j) { 00498 for (int i=0; i < numRowsC; ++i) { 00499 C_view[strideC*j+i] = destBuff[numRowsC*j+i]; 00500 } 00501 } 00502 } 00503 } 00504 } 00505 00507 static void 00508 MvDot (const MV& A, const MV& B, std::vector<Scalar> &dots) 00509 { 00510 const size_t numVecs = A.getNumVectors (); 00511 TEUCHOS_TEST_FOR_EXCEPTION( 00512 numVecs != B.getNumVectors (), std::invalid_argument, 00513 "Anasazi::MultiVecTraits::MvDot(A,B,dots): " 00514 "A and B must have the same number of columns. " 00515 "A has " << numVecs << " column(s), " 00516 "but B has " << B.getNumVectors () << " column(s)."); 00517 #ifdef HAVE_TPETRA_DEBUG 00518 TEUCHOS_TEST_FOR_EXCEPTION( 00519 dots.size() < numVecs, std::invalid_argument, 00520 "Anasazi::MultiVecTraits::MvDot(A,B,dots): " 00521 "The output array 'dots' must have room for all dot products. " 00522 "A and B each have " << numVecs << " column(s), " 00523 "but 'dots' only has " << dots.size() << " entry(/ies)."); 00524 #endif // HAVE_TPETRA_DEBUG 00525 00526 Teuchos::ArrayView<Scalar> av (dots); 00527 A.dot (B, av (0, numVecs)); 00528 } 00529 00531 static void 00532 MvNorm (const MV& mv, 00533 std::vector<typename Teuchos::ScalarTraits<Scalar>::magnitudeType> &normvec) 00534 { 00535 typedef typename Teuchos::ScalarTraits<Scalar>::magnitudeType magnitude_type; 00536 #ifdef HAVE_TPETRA_DEBUG 00537 TEUCHOS_TEST_FOR_EXCEPTION( 00538 normvec.size () < static_cast<std::vector<int>::size_type> (mv.getNumVectors ()), 00539 std::invalid_argument, 00540 "Anasazi::MultiVecTraits::MvNorm(mv,normvec): The normvec output " 00541 "argument must have at least as many entries as the number of vectors " 00542 "(columns) in the MultiVector mv. normvec.size() = " << normvec.size () 00543 << " < mv.getNumVectors() = " << mv.getNumVectors () << "."); 00544 #endif // HAVE_TPETRA_DEBUG 00545 Teuchos::ArrayView<magnitude_type> av (normvec); 00546 mv.norm2 (av (0, mv.getNumVectors ())); 00547 } 00548 00549 static void 00550 SetBlock (const MV& A, const std::vector<int>& index, MV& mv) 00551 { 00552 using Teuchos::Range1D; 00553 using Teuchos::RCP; 00554 const size_t inNumVecs = A.getNumVectors (); 00555 #ifdef HAVE_TPETRA_DEBUG 00556 TEUCHOS_TEST_FOR_EXCEPTION( 00557 inNumVecs < static_cast<size_t> (index.size ()), std::invalid_argument, 00558 "Anasazi::MultiVecTraits::SetBlock(A,index,mv): 'index' argument must " 00559 "have no more entries as the number of columns in the input MultiVector" 00560 " A. A.getNumVectors() = " << inNumVecs << " < index.size () = " 00561 << index.size () << "."); 00562 #endif // HAVE_TPETRA_DEBUG 00563 RCP<MV> mvsub = CloneViewNonConst (mv, index); 00564 if (inNumVecs > static_cast<size_t> (index.size ())) { 00565 RCP<const MV> Asub = A.subView (Range1D (0, index.size () - 1)); 00566 Tpetra::deep_copy (*mvsub, *Asub); 00567 } else { 00568 Tpetra::deep_copy (*mvsub, A); 00569 } 00570 } 00571 00572 static void 00573 SetBlock (const MV& A, const Teuchos::Range1D& index, MV& mv) 00574 { 00575 // Range1D bounds are signed; size_t is unsigned. 00576 // Assignment of Tpetra::MultiVector is a deep copy. 00577 00578 // Tpetra::MultiVector::getNumVectors() returns size_t. It's 00579 // fair to assume that the number of vectors won't overflow int, 00580 // since the typical use case of multivectors involves few 00581 // columns, but it's friendly to check just in case. 00582 const size_t maxInt = 00583 static_cast<size_t> (Teuchos::OrdinalTraits<int>::max ()); 00584 const bool overflow = 00585 maxInt < A.getNumVectors () && maxInt < mv.getNumVectors (); 00586 if (overflow) { 00587 std::ostringstream os; 00588 os << "Anasazi::MultiVecTraits::SetBlock(A, index=[" << index.lbound () 00589 << ", " << index.ubound () << "], mv): "; 00590 TEUCHOS_TEST_FOR_EXCEPTION( 00591 maxInt < A.getNumVectors (), std::range_error, os.str () << "Number " 00592 "of columns (size_t) in the input MultiVector 'A' overflows int."); 00593 TEUCHOS_TEST_FOR_EXCEPTION( 00594 maxInt < mv.getNumVectors (), std::range_error, os.str () << "Number " 00595 "of columns (size_t) in the output MultiVector 'mv' overflows int."); 00596 } 00597 // We've already validated the static casts above. 00598 const int numColsA = static_cast<int> (A.getNumVectors ()); 00599 const int numColsMv = static_cast<int> (mv.getNumVectors ()); 00600 // 'index' indexes into mv; it's the index set of the target. 00601 const bool validIndex = 00602 index.lbound () >= 0 && index.ubound () < numColsMv; 00603 // We can't take more columns out of A than A has. 00604 const bool validSource = index.size () <= numColsA; 00605 00606 if (! validIndex || ! validSource) { 00607 std::ostringstream os; 00608 os << "Anasazi::MultiVecTraits::SetBlock(A, index=[" << index.lbound () 00609 << ", " << index.ubound () << "], mv): "; 00610 TEUCHOS_TEST_FOR_EXCEPTION( 00611 index.lbound() < 0, std::invalid_argument, 00612 os.str() << "Range lower bound must be nonnegative."); 00613 TEUCHOS_TEST_FOR_EXCEPTION( 00614 index.ubound() >= numColsMv, std::invalid_argument, 00615 os.str() << "Range upper bound must be less than the number of " 00616 "columns " << numColsA << " in the 'mv' output argument."); 00617 TEUCHOS_TEST_FOR_EXCEPTION( 00618 index.size() > numColsA, std::invalid_argument, 00619 os.str() << "Range must have no more elements than the number of " 00620 "columns " << numColsA << " in the 'A' input argument."); 00621 TEUCHOS_TEST_FOR_EXCEPTION( 00622 true, std::logic_error, "Should never get here!"); 00623 } 00624 00625 // View of the relevant column(s) of the target multivector mv. 00626 // We avoid view creation overhead by only creating a view if 00627 // the index range is different than [0, (# columns in mv) - 1]. 00628 Teuchos::RCP<MV> mv_view; 00629 if (index.lbound () == 0 && index.ubound () + 1 == numColsMv) { 00630 mv_view = Teuchos::rcpFromRef (mv); // Non-const, non-owning RCP 00631 } else { 00632 mv_view = CloneViewNonConst (mv, index); 00633 } 00634 00635 // View of the relevant column(s) of the source multivector A. 00636 // If A has fewer columns than mv_view, then create a view of 00637 // the first index.size() columns of A. 00638 Teuchos::RCP<const MV> A_view; 00639 if (index.size () == numColsA) { 00640 A_view = Teuchos::rcpFromRef (A); // Const, non-owning RCP 00641 } else { 00642 A_view = CloneView (A, Teuchos::Range1D (0, index.size () - 1)); 00643 } 00644 00645 Tpetra::deep_copy (*mv_view, *A_view); 00646 } 00647 00648 static void Assign (const MV& A, MV& mv) 00649 { 00650 const char errPrefix[] = "Anasazi::MultiVecTraits::Assign(A, mv): "; 00651 00652 // Range1D bounds are signed; size_t is unsigned. 00653 // Assignment of Tpetra::MultiVector is a deep copy. 00654 00655 // Tpetra::MultiVector::getNumVectors() returns size_t. It's 00656 // fair to assume that the number of vectors won't overflow int, 00657 // since the typical use case of multivectors involves few 00658 // columns, but it's friendly to check just in case. 00659 const size_t maxInt = 00660 static_cast<size_t> (Teuchos::OrdinalTraits<int>::max ()); 00661 const bool overflow = 00662 maxInt < A.getNumVectors () && maxInt < mv.getNumVectors (); 00663 if (overflow) { 00664 TEUCHOS_TEST_FOR_EXCEPTION( 00665 maxInt < A.getNumVectors(), std::range_error, 00666 errPrefix << "Number of columns in the input multivector 'A' " 00667 "(a size_t) overflows int."); 00668 TEUCHOS_TEST_FOR_EXCEPTION( 00669 maxInt < mv.getNumVectors(), std::range_error, 00670 errPrefix << "Number of columns in the output multivector 'mv' " 00671 "(a size_t) overflows int."); 00672 TEUCHOS_TEST_FOR_EXCEPTION( 00673 true, std::logic_error, "Should never get here!"); 00674 } 00675 // We've already validated the static casts above. 00676 const int numColsA = static_cast<int> (A.getNumVectors ()); 00677 const int numColsMv = static_cast<int> (mv.getNumVectors ()); 00678 if (numColsA > numColsMv) { 00679 TEUCHOS_TEST_FOR_EXCEPTION( 00680 numColsA > numColsMv, std::invalid_argument, 00681 errPrefix << "Input multivector 'A' has " << numColsA << " columns, " 00682 "but output multivector 'mv' has only " << numColsMv << " columns."); 00683 TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error, "Should never get here!"); 00684 } 00685 if (numColsA == numColsMv) { 00686 Tpetra::deep_copy (mv, A); 00687 } else { 00688 Teuchos::RCP<MV> mv_view = 00689 CloneViewNonConst (mv, Teuchos::Range1D (0, numColsA - 1)); 00690 Tpetra::deep_copy (*mv_view, A); 00691 } 00692 } 00693 00694 static void MvRandom (MV& mv) { 00695 mv.randomize (); 00696 } 00697 00698 static void 00699 MvInit (MV& mv, const Scalar alpha = Teuchos::ScalarTraits<Scalar>::zero ()) 00700 { 00701 mv.putScalar (alpha); 00702 } 00703 00704 static void MvPrint (const MV& mv, std::ostream& os) { 00705 mv.print (os); 00706 } 00707 00708 #ifdef HAVE_ANASAZI_TSQR 00709 00710 00711 typedef Tpetra::TsqrAdaptor<Tpetra::MultiVector<Scalar, LO, GO, Node> > tsqr_adaptor_type; 00712 #endif // HAVE_ANASAZI_TSQR 00713 }; 00714 00716 template <class Scalar, class LO, class GO, class Node> 00717 class OperatorTraits<Scalar, 00718 Tpetra::MultiVector<Scalar,LO,GO,Node>, 00719 Tpetra::Operator<Scalar,LO,GO,Node> > 00720 { 00721 public: 00722 static void 00723 Apply (const Tpetra::Operator<Scalar,LO,GO,Node>& Op, 00724 const Tpetra::MultiVector<Scalar,LO,GO,Node>& X, 00725 Tpetra::MultiVector<Scalar,LO,GO,Node>& Y) 00726 { 00727 Op.apply (X, Y, Teuchos::NO_TRANS); 00728 } 00729 }; 00730 00731 } // end of Anasazi namespace 00732 00733 #endif 00734 // end of file ANASAZI_TPETRA_ADAPTER_HPP
1.7.6.1