|
Stratimikos Package Browser (Single Doxygen Collection)
Version of the Day
|
00001 // @HEADER 00002 // *********************************************************************** 00003 // 00004 // Stratimikos: Thyra-based strategies for linear solvers 00005 // Copyright (2006) 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 // 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 Roscoe A. Bartlett (rabartl@sandia.gov) 00038 // 00039 // *********************************************************************** 00040 // @HEADER 00041 00052 #ifndef BELOS_THYRA_ADAPTER_HPP 00053 #define BELOS_THYRA_ADAPTER_HPP 00054 00055 #include "BelosConfigDefs.hpp" 00056 #include "BelosMultiVecTraits.hpp" 00057 #include "BelosOperatorTraits.hpp" 00058 00059 #include <Thyra_DetachedMultiVectorView.hpp> 00060 #include <Thyra_MultiVectorBase.hpp> 00061 #include <Thyra_MultiVectorStdOps.hpp> 00062 #ifdef HAVE_BELOS_TSQR 00063 # include <Thyra_TsqrAdaptor.hpp> 00064 #endif // HAVE_BELOS_TSQR 00065 00066 namespace Belos { 00067 00069 // 00070 // Implementation of the Belos::MultiVecTraits for Thyra::MultiVectorBase 00071 // 00073 00080 template<class ScalarType> 00081 class MultiVecTraits< ScalarType, Thyra::MultiVectorBase<ScalarType> > 00082 { 00083 private: 00084 typedef Thyra::MultiVectorBase<ScalarType> TMVB; 00085 typedef Teuchos::ScalarTraits<ScalarType> ST; 00086 typedef typename ST::magnitudeType magType; 00087 00088 public: 00089 00092 00097 static Teuchos::RCP<TMVB> Clone( const TMVB& mv, const int numvecs ) 00098 { 00099 Teuchos::RCP<TMVB> c = Thyra::createMembers( mv.range(), numvecs ); 00100 return c; 00101 } 00102 00107 static Teuchos::RCP<TMVB> CloneCopy( const TMVB& mv ) 00108 { 00109 int numvecs = mv.domain()->dim(); 00110 // create the new multivector 00111 Teuchos::RCP< TMVB > cc = Thyra::createMembers( mv.range(), numvecs ); 00112 // copy the data from the source multivector to the new multivector 00113 Thyra::assign(cc.ptr(), mv); 00114 return cc; 00115 } 00116 00122 static Teuchos::RCP<TMVB> CloneCopy( const TMVB& mv, const std::vector<int>& index ) 00123 { 00124 int numvecs = index.size(); 00125 // create the new multivector 00126 Teuchos::RCP<TMVB> cc = Thyra::createMembers( mv.range(), numvecs ); 00127 // create a view to the relevant part of the source multivector 00128 Teuchos::RCP<const TMVB> view = mv.subView(index); 00129 // copy the data from the relevant view to the new multivector 00130 Thyra::assign(cc.ptr(), *view); 00131 return cc; 00132 } 00133 00134 static Teuchos::RCP<TMVB> 00135 CloneCopy (const TMVB& mv, const Teuchos::Range1D& index) 00136 { 00137 const int numVecs = index.size(); 00138 // Create the new multivector 00139 Teuchos::RCP<TMVB> cc = Thyra::createMembers (mv.range(), numVecs); 00140 // Create a view to the relevant part of the source multivector 00141 Teuchos::RCP<const TMVB> view = mv.subView (index); 00142 // Copy the data from the view to the new multivector. 00143 Thyra::assign (cc.ptr(), *view); 00144 return cc; 00145 } 00146 00152 static Teuchos::RCP<TMVB> CloneViewNonConst( TMVB& mv, const std::vector<int>& index ) 00153 { 00154 int numvecs = index.size(); 00155 00156 // We do not assume that the indices are sorted, nor do we check that 00157 // index.size() > 0. This code is fail-safe, in the sense that a zero 00158 // length index std::vector will pass the error on the Thyra. 00159 00160 // Thyra has two ways to create an indexed View: 00161 // * contiguous (via a range of columns) 00162 // * indexed (via a std::vector of column indices) 00163 // The former is significantly more efficient than the latter, in terms of 00164 // computations performed with/against the created view. 00165 // We will therefore check to see if the given indices are contiguous, and 00166 // if so, we will use the contiguous view creation method. 00167 00168 int lb = index[0]; 00169 bool contig = true; 00170 for (int i=0; i<numvecs; i++) { 00171 if (lb+i != index[i]) contig = false; 00172 } 00173 00174 Teuchos::RCP< TMVB > cc; 00175 if (contig) { 00176 const Thyra::Range1D rng(lb,lb+numvecs-1); 00177 // create a contiguous view to the relevant part of the source multivector 00178 cc = mv.subView(rng); 00179 } 00180 else { 00181 // create an indexed view to the relevant part of the source multivector 00182 cc = mv.subView(index); 00183 } 00184 return cc; 00185 } 00186 00187 static Teuchos::RCP<TMVB> 00188 CloneViewNonConst (TMVB& mv, const Teuchos::Range1D& index) 00189 { 00190 // We let Thyra be responsible for checking that the index range 00191 // is nonempty. 00192 // 00193 // Create and return a contiguous view to the relevant part of 00194 // the source multivector. 00195 return mv.subView (index); 00196 } 00197 00198 00204 static Teuchos::RCP<const TMVB> CloneView( const TMVB& mv, const std::vector<int>& index ) 00205 { 00206 int numvecs = index.size(); 00207 00208 // We do not assume that the indices are sorted, nor do we check that 00209 // index.size() > 0. This code is fail-safe, in the sense that a zero 00210 // length index std::vector will pass the error on the Thyra. 00211 00212 // Thyra has two ways to create an indexed View: 00213 // * contiguous (via a range of columns) 00214 // * indexed (via a std::vector of column indices) 00215 // The former is significantly more efficient than the latter, in terms of 00216 // computations performed with/against the created view. 00217 // We will therefore check to see if the given indices are contiguous, and 00218 // if so, we will use the contiguous view creation method. 00219 00220 int lb = index[0]; 00221 bool contig = true; 00222 for (int i=0; i<numvecs; i++) { 00223 if (lb+i != index[i]) contig = false; 00224 } 00225 00226 Teuchos::RCP< const TMVB > cc; 00227 if (contig) { 00228 const Thyra::Range1D rng(lb,lb+numvecs-1); 00229 // create a contiguous view to the relevant part of the source multivector 00230 cc = mv.subView(rng); 00231 } 00232 else { 00233 // create an indexed view to the relevant part of the source multivector 00234 cc = mv.subView(index); 00235 } 00236 return cc; 00237 } 00238 00239 static Teuchos::RCP<const TMVB> 00240 CloneView (const TMVB& mv, const Teuchos::Range1D& index) 00241 { 00242 // We let Thyra be responsible for checking that the index range 00243 // is nonempty. 00244 // 00245 // Create and return a contiguous view to the relevant part of 00246 // the source multivector. 00247 return mv.subView (index); 00248 } 00249 00251 00254 00256 static int GetVecLength( const TMVB& mv ) 00257 { return mv.range()->dim(); } 00258 00260 static int GetNumberVecs( const TMVB& mv ) 00261 { return mv.domain()->dim(); } 00262 00264 00267 00270 static void MvTimesMatAddMv( const ScalarType alpha, const TMVB& A, 00271 const Teuchos::SerialDenseMatrix<int,ScalarType>& B, 00272 const ScalarType beta, TMVB& mv ) 00273 { 00274 using Teuchos::arrayView; using Teuchos::arcpFromArrayView; 00275 const int m = B.numRows(); 00276 const int n = B.numCols(); 00277 // Create a view of the B object! 00278 Teuchos::RCP< const TMVB > 00279 B_thyra = Thyra::createMembersView( 00280 A.domain(), 00281 RTOpPack::ConstSubMultiVectorView<ScalarType>( 00282 0, m, 0, n, 00283 arcpFromArrayView(arrayView(&B(0,0), B.stride()*B.numCols())), B.stride() 00284 ) 00285 ); 00286 // perform the operation via A: mv <- alpha*A*B_thyra + beta*mv 00287 Thyra::apply<ScalarType>(A, Thyra::NOTRANS, *B_thyra, Teuchos::outArg(mv), alpha, beta); 00288 } 00289 00292 static void MvAddMv( const ScalarType alpha, const TMVB& A, 00293 const ScalarType beta, const TMVB& B, TMVB& mv ) 00294 { 00295 typedef Teuchos::ScalarTraits<ScalarType> ST; 00296 using Teuchos::tuple; using Teuchos::ptrInArg; using Teuchos::inoutArg; 00297 00298 Thyra::linear_combination<ScalarType>( 00299 tuple(alpha, beta)(), tuple(ptrInArg(A), ptrInArg(B))(), ST::zero(), inoutArg(mv)); 00300 } 00301 00304 static void MvScale ( TMVB& mv, const ScalarType alpha ) 00305 { Thyra::scale(alpha, Teuchos::inoutArg(mv)); } 00306 00309 static void MvScale (TMVB& mv, const std::vector<ScalarType>& alpha) 00310 { 00311 for (unsigned int i=0; i<alpha.size(); i++) { 00312 Thyra::scale<ScalarType> (alpha[i], mv.col(i).ptr()); 00313 } 00314 } 00315 00318 static void MvTransMv( const ScalarType alpha, const TMVB& A, const TMVB& mv, 00319 Teuchos::SerialDenseMatrix<int,ScalarType>& B ) 00320 { 00321 using Teuchos::arrayView; using Teuchos::arcpFromArrayView; 00322 // Create a multivector to hold the result (m by n) 00323 int m = A.domain()->dim(); 00324 int n = mv.domain()->dim(); 00325 // Create a view of the B object! 00326 Teuchos::RCP< TMVB > 00327 B_thyra = Thyra::createMembersView( 00328 A.domain(), 00329 RTOpPack::SubMultiVectorView<ScalarType>( 00330 0, m, 0, n, 00331 arcpFromArrayView(arrayView(&B(0,0), B.stride()*B.numCols())), B.stride() 00332 ) 00333 ); 00334 Thyra::apply<ScalarType>(A, Thyra::CONJTRANS, mv, B_thyra.ptr(), alpha); 00335 } 00336 00340 static void MvDot( const TMVB& mv, const TMVB& A, std::vector<ScalarType>& b ) 00341 { Thyra::dots(mv, A, Teuchos::arrayViewFromVector(b)); } 00342 00344 00347 00351 static void MvNorm( const TMVB& mv, std::vector<magType>& normvec, 00352 NormType type = TwoNorm ) 00353 { Thyra::norms_2(mv, Teuchos::arrayViewFromVector(normvec)); } 00354 00356 00359 00362 static void SetBlock( const TMVB& A, const std::vector<int>& index, TMVB& mv ) 00363 { 00364 // Extract the "numvecs" columns of mv indicated by the index std::vector. 00365 int numvecs = index.size(); 00366 std::vector<int> indexA(numvecs); 00367 int numAcols = A.domain()->dim(); 00368 for (int i=0; i<numvecs; i++) { 00369 indexA[i] = i; 00370 } 00371 // Thyra::assign requires that both arguments have the same number of 00372 // vectors. Enforce this, by shrinking one to match the other. 00373 if ( numAcols < numvecs ) { 00374 // A does not have enough columns to satisfy index_plus. Shrink 00375 // index_plus. 00376 numvecs = numAcols; 00377 } 00378 else if ( numAcols > numvecs ) { 00379 numAcols = numvecs; 00380 indexA.resize( numAcols ); 00381 } 00382 // create a view to the relevant part of the source multivector 00383 Teuchos::RCP< const TMVB > relsource = A.subView(indexA); 00384 // create a view to the relevant part of the destination multivector 00385 Teuchos::RCP< TMVB > reldest = mv.subView(index); 00386 // copy the data to the destination multivector subview 00387 Thyra::assign(reldest.ptr(), *relsource); 00388 } 00389 00390 static void 00391 SetBlock (const TMVB& A, const Teuchos::Range1D& index, TMVB& mv) 00392 { 00393 const int numColsA = A.domain()->dim(); 00394 const int numColsMv = mv.domain()->dim(); 00395 // 'index' indexes into mv; it's the index set of the target. 00396 const bool validIndex = index.lbound() >= 0 && index.ubound() < numColsMv; 00397 // We can't take more columns out of A than A has. 00398 const bool validSource = index.size() <= numColsA; 00399 00400 if (! validIndex || ! validSource) 00401 { 00402 std::ostringstream os; 00403 os << "Belos::MultiVecTraits<Scalar, Thyra::MultiVectorBase<Scalar> " 00404 ">::SetBlock(A, [" << index.lbound() << ", " << index.ubound() 00405 << "], mv): "; 00406 TEUCHOS_TEST_FOR_EXCEPTION(index.lbound() < 0, std::invalid_argument, 00407 os.str() << "Range lower bound must be nonnegative."); 00408 TEUCHOS_TEST_FOR_EXCEPTION(index.ubound() >= numColsMv, std::invalid_argument, 00409 os.str() << "Range upper bound must be less than " 00410 "the number of columns " << numColsA << " in the " 00411 "'mv' output argument."); 00412 TEUCHOS_TEST_FOR_EXCEPTION(index.size() > numColsA, std::invalid_argument, 00413 os.str() << "Range must have no more elements than" 00414 " the number of columns " << numColsA << " in the " 00415 "'A' input argument."); 00416 TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error, "Should never get here!"); 00417 } 00418 00419 // View of the relevant column(s) of the target multivector mv. 00420 // We avoid view creation overhead by only creating a view if 00421 // the index range is different than [0, (# columns in mv) - 1]. 00422 Teuchos::RCP<TMVB> mv_view; 00423 if (index.lbound() == 0 && index.ubound()+1 == numColsMv) 00424 mv_view = Teuchos::rcpFromRef (mv); // Non-const, non-owning RCP 00425 else 00426 mv_view = mv.subView (index); 00427 00428 // View of the relevant column(s) of the source multivector A. 00429 // If A has fewer columns than mv_view, then create a view of 00430 // the first index.size() columns of A. 00431 Teuchos::RCP<const TMVB> A_view; 00432 if (index.size() == numColsA) 00433 A_view = Teuchos::rcpFromRef (A); // Const, non-owning RCP 00434 else 00435 A_view = A.subView (Teuchos::Range1D(0, index.size()-1)); 00436 00437 // Copy the data to the destination multivector. 00438 Thyra::assign(mv_view.ptr(), *A_view); 00439 } 00440 00441 static void 00442 Assign (const TMVB& A, TMVB& mv) 00443 { 00444 const int numColsA = A.domain()->dim(); 00445 const int numColsMv = mv.domain()->dim(); 00446 if (numColsA > numColsMv) 00447 { 00448 std::ostringstream os; 00449 os << "Belos::MultiVecTraits<Scalar, Thyra::MultiVectorBase<Scalar>" 00450 " >::Assign(A, mv): "; 00451 TEUCHOS_TEST_FOR_EXCEPTION(numColsA > numColsMv, std::invalid_argument, 00452 os.str() << "Input multivector 'A' has " 00453 << numColsA << " columns, but output multivector " 00454 "'mv' has only " << numColsMv << " columns."); 00455 TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error, "Should never get here!"); 00456 } 00457 // Copy the data to the destination multivector. 00458 if (numColsA == numColsMv) { 00459 Thyra::assign (Teuchos::outArg (mv), A); 00460 } else { 00461 Teuchos::RCP<TMVB> mv_view = 00462 CloneViewNonConst (mv, Teuchos::Range1D(0, numColsA-1)); 00463 Thyra::assign (mv_view.ptr(), A); 00464 } 00465 } 00466 00469 static void MvRandom( TMVB& mv ) 00470 { 00471 // Thyra::randomize generates via a uniform distribution on [l,u] 00472 // We will use this to generate on [-1,1] 00473 Thyra::randomize<ScalarType>( 00474 -Teuchos::ScalarTraits<ScalarType>::one(), 00475 Teuchos::ScalarTraits<ScalarType>::one(), 00476 Teuchos::outArg(mv)); 00477 } 00478 00480 static void 00481 MvInit (TMVB& mv, ScalarType alpha = Teuchos::ScalarTraits<ScalarType>::zero()) 00482 { 00483 Thyra::assign (Teuchos::outArg (mv), alpha); 00484 } 00485 00487 00490 00493 static void MvPrint( const TMVB& mv, std::ostream& os ) 00494 { os << describe(mv,Teuchos::VERB_EXTREME); } 00495 00497 00498 #ifdef HAVE_BELOS_TSQR 00499 00500 00501 00502 00503 00504 typedef Thyra::TsqrAdaptor< ScalarType > tsqr_adaptor_type; 00505 #endif // HAVE_BELOS_TSQR 00506 }; 00507 00509 // 00510 // Implementation of the Belos::OperatorTraits for Thyra::LinearOpBase 00511 // 00513 00521 template<class ScalarType> 00522 class OperatorTraits <ScalarType, 00523 Thyra::MultiVectorBase<ScalarType>, 00524 Thyra::LinearOpBase<ScalarType> > 00525 { 00526 private: 00527 typedef Thyra::MultiVectorBase<ScalarType> TMVB; 00528 typedef Thyra::LinearOpBase<ScalarType> TLOB; 00529 00530 public: 00546 static void 00547 Apply (const TLOB& Op, 00548 const TMVB& x, 00549 TMVB& y, 00550 ETrans trans = NOTRANS) 00551 { 00552 Thyra::EOpTransp whichOp; 00553 00554 // We don't check here whether the operator implements the 00555 // requested operation. Call HasApplyTranspose() to check. 00556 // Thyra::LinearOpBase implementations are not required to 00557 // implement NOTRANS. However, Belos needs NOTRANS 00558 // (obviously!), so we assume that Op implements NOTRANS. 00559 if (trans == NOTRANS) 00560 whichOp = Thyra::NOTRANS; 00561 else if (trans == TRANS) 00562 whichOp = Thyra::TRANS; 00563 else if (trans == CONJTRANS) 00564 whichOp = Thyra::CONJTRANS; 00565 else 00566 TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument, 00567 "Belos::OperatorTraits::Apply (Thyra specialization): " 00568 "'trans' argument must be neither NOTRANS=" << NOTRANS 00569 << ", TRANS=" << TRANS << ", or CONJTRANS=" << CONJTRANS 00570 << ", but instead has an invalid value of " << trans << "."); 00571 Thyra::apply<ScalarType>(Op, whichOp, x, Teuchos::outArg(y)); 00572 } 00573 00575 static bool HasApplyTranspose (const TLOB& Op) 00576 { 00577 typedef Teuchos::ScalarTraits<ScalarType> STS; 00578 00579 // Thyra::LinearOpBase's interface lets you check whether the 00580 // operator implements any of all four possible combinations of 00581 // conjugation and transpose. Belos only needs transpose 00582 // (TRANS) if the operator is real; in that case, Apply() does 00583 // the same thing with trans = CONJTRANS or TRANS. If the 00584 // operator is complex, Belos needs both transpose and conjugate 00585 // transpose (CONJTRANS) if the operator is complex. 00586 return Op.opSupported (Thyra::TRANS) && 00587 (! STS::isComplex || Op.opSupported (Thyra::CONJTRANS)); 00588 } 00589 }; 00590 00591 // Partial specialization for MV=Thyra::MultiVectorBase. This supports 64-bit types 00592 template<class ScalarType> 00593 class MultiVecTraitsExt<ScalarType, Thyra::MultiVectorBase<ScalarType> > { 00594 public: 00595 typedef Thyra::MultiVectorBase<ScalarType> MV; 00596 static ptrdiff_t GetGlobalLength( const MV& mv ) { 00597 return Teuchos::as<ptrdiff_t>(mv.range()->dim()); 00598 } 00599 }; 00600 00601 } // end of Belos namespace 00602 00603 #endif 00604 // end of file BELOS_THYRA_ADAPTER_HPP
1.7.6.1