|
Ifpack2 Templated Preconditioning Package
Version 1.0
|
00001 /*@HEADER 00002 // *********************************************************************** 00003 // 00004 // Ifpack2: Tempated Object-Oriented Algebraic Preconditioner Package 00005 // Copyright (2009) 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 Michael A. Heroux (maherou@sandia.gov) 00038 // 00039 // *********************************************************************** 00040 //@HEADER 00041 */ 00042 00043 #ifndef IFPACK2_KRYLOV_DEF_HPP 00044 #define IFPACK2_KRYLOV_DEF_HPP 00045 00046 #include "Ifpack2_Krylov_decl.hpp" 00047 00048 namespace Ifpack2 { 00049 00050 template <class MatrixType> 00051 Krylov<MatrixType>:: 00052 Krylov (const Teuchos::RCP<const row_matrix_type>& A) : 00053 A_ (A), 00054 // Default values 00055 iterationType_ ("GMRES"), 00056 numIters_ (5), 00057 resTol_ (0.001), // FIXME (mfh 17 Jan 2014) Make a function of STS::eps() 00058 BlockSize_ (1), 00059 ZeroStartingSolution_ (true), 00060 PreconditionerType_ (1), 00061 // General 00062 Condest_ (-STM::one ()), 00063 IsInitialized_ (false), 00064 IsComputed_ (false), 00065 NumInitialize_ (0), 00066 NumCompute_ (0), 00067 NumApply_ (0), 00068 InitializeTime_ (0.0), 00069 ComputeTime_ (0.0), 00070 ApplyTime_ (0.0) 00071 {} 00072 00073 00074 template <class MatrixType> 00075 Krylov<MatrixType>::~Krylov() {} 00076 00077 00078 template <class MatrixType> 00079 void Krylov<MatrixType>::setMatrix (const Teuchos::RCP<const row_matrix_type>& A) 00080 { 00081 // Check in serial or one-process mode if the matrix is square. 00082 TEUCHOS_TEST_FOR_EXCEPTION( 00083 ! A.is_null () && A->getComm ()->getSize () == 1 && 00084 A->getNodeNumRows () != A->getNodeNumCols (), 00085 std::runtime_error, "Ifpack2::Krylov::setMatrix: If A's communicator only " 00086 "contains one process, then A must be square. Instead, you provided a " 00087 "matrix A with " << A->getNodeNumRows () << " rows and " 00088 << A->getNodeNumCols () << " columns."); 00089 00090 // It's legal for A to be null; in that case, you may not call 00091 // initialize() until calling setMatrix() with a nonnull input. 00092 // Regardless, setting the matrix invalidates any previous 00093 // factorization. 00094 IsInitialized_ = false; 00095 IsComputed_ = false; 00096 Condest_ = -STM::one (); 00097 00098 A_ = A; 00099 } 00100 00101 00102 template <class MatrixType> 00103 void Krylov<MatrixType>::setParameters (const Teuchos::ParameterList& plist) 00104 { 00105 using Teuchos::as; 00106 using Teuchos::ParameterList; 00107 using Teuchos::Exceptions::InvalidParameterName; 00108 using Teuchos::Exceptions::InvalidParameterType; 00109 00110 // FIXME (mfh 12 Sep 2014) Don't rewrite Belos::SolverFactory!!! Use 00111 // that instead. 00112 00113 ParameterList params = plist; 00114 00115 // Get the current parameters' values. We don't assign to the 00116 // instance data directly until we've gotten all the parameters. 00117 // This ensures "transactional" semantics, so that if attempting to 00118 // get some parameter throws an exception, the class' state doesn't 00119 // change. 00120 magnitude_type resTol = resTol_; 00121 int numIters = numIters_; 00122 std::string iterType = iterationType_; 00123 int blockSize = BlockSize_; 00124 bool zeroStartingSolution = ZeroStartingSolution_; 00125 int precType = PreconditionerType_; 00126 00127 // 00128 // Get the "krylov: iteration type" parameter. 00129 // 00130 // We prefer std::string (name of Belos solver), but allow int 00131 // ("enum" value) for backwards compatibility. 00132 // 00133 bool gotIterType = false; 00134 try { 00135 iterType = params.get<std::string> ("krylov: iteration type"); 00136 gotIterType = true; 00137 } 00138 catch (InvalidParameterName) { 00139 gotIterType = true; // the parameter is not there, so don't try to get it anymore 00140 } 00141 catch (InvalidParameterType) { 00142 // Perhaps the user specified it as int. 00143 } 00144 // If it's not string, it has to be int. 00145 // We've already checked whether the name exists. 00146 if (! gotIterType) { 00147 const int iterTypeInt = params.get<int> ("krylov: iteration type"); 00148 gotIterType = true; 00149 00150 if (iterTypeInt == 1) { 00151 iterType = "GMRES"; 00152 } else if (iterTypeInt == 2) { 00153 iterType = "CG"; 00154 } else { 00155 TEUCHOS_TEST_FOR_EXCEPTION( 00156 true, std::invalid_argument, "Ifpack2::Krylov::setParameters: Invalid " 00157 "\"krylov: iteration type\" value " << iterTypeInt << ". Valid int " 00158 "values are 1 (GMRES) and 2 (CG). Please prefer setting this " 00159 "parameter as a string (the name of the Krylov solver to use)."); 00160 } 00161 } 00162 00163 resTol = params.get ("krylov: residual tolerance", resTol); 00164 numIters = params.get ("krylov: number of iterations", numIters); 00165 blockSize = params.get ("krylov: block size", blockSize); 00166 zeroStartingSolution = params.get ("krylov: zero starting solution", 00167 zeroStartingSolution); 00168 precType = params.get ("krylov: preconditioner type", precType); 00169 00170 // Separate preconditioner parameters into another list 00171 // 00172 // FIXME (mfh 17 Jan 2014) Inner preconditioner's parameters should 00173 // be a sublist, not part of the main list!!! 00174 if (PreconditionerType_ == 1) { 00175 precParams_.set ("relaxation: sweeps", 00176 params.get ("relaxation: sweeps", 1)); 00177 precParams_.set ("relaxation: damping factor", 00178 params.get ("relaxation: damping factor", (scalar_type) 1.0)); 00179 precParams_.set ("relaxation: min diagonal value", 00180 params.get ("relaxation: min diagonal value", STS::one ())); 00181 precParams_.set ("relaxation: zero starting solution", 00182 params.get ("relaxation: zero starting solution", true)); 00183 precParams_.set ("relaxation: backward mode", 00184 params.get ("relaxation: backward mode", false)); 00185 } 00186 // FIXME (mfh 17 Jan 2014) AdditiveSchwarz's ParameterList no longer 00187 // takes parameters for its subdomain solver! You have to pass them 00188 // into a sublist. 00189 if (PreconditionerType_ == 2 || PreconditionerType_ == 3) { 00190 // FIXME (mfh 17 Jan 2014) should be an integer, given how ILUT 00191 // works! Furthermore, this parameter does not mean what you 00192 // think it means. 00193 precParams_.set ("fact: ilut level-of-fill", 00194 params.get ("fact: ilut level-of-fill", (double) 1.0)); 00195 precParams_.set ("fact: iluk level-of-fill", 00196 params.get ("fact: iluk level-of-fill", (double) 1.0)); 00197 // FIXME (mfh 17 Jan 2014) scalar_type or magnitude_type? not 00198 // sure, but double is definitely wrong. 00199 precParams_.set ("fact: absolute threshold", 00200 params.get ("fact: absolute threshold", (double) 0.0)); 00201 // FIXME (mfh 17 Jan 2014) scalar_type or magnitude_type? not 00202 // sure, but double is definitely wrong. 00203 precParams_.set ("fact: relative threshold", 00204 params.get("fact: relative threshold", (double) 1.0)); 00205 // FIXME (mfh 17 Jan 2014) scalar_type or magnitude_type? not 00206 // sure, but double is definitely wrong. 00207 precParams_.set ("fact: relax value", 00208 params.get ("fact: relax value", (double) 0.0)); 00209 } 00210 00211 // "Commit" the new values to the instance data. 00212 iterationType_ = iterType; 00213 numIters_ = numIters; 00214 resTol_ = resTol; 00215 BlockSize_ = blockSize; 00216 ZeroStartingSolution_ = zeroStartingSolution; 00217 PreconditionerType_ = precType; 00218 } 00219 00220 00221 template <class MatrixType> 00222 Teuchos::RCP<const Teuchos::Comm<int> > 00223 Krylov<MatrixType>::getComm () const { 00224 TEUCHOS_TEST_FOR_EXCEPTION( 00225 A_.is_null (), std::runtime_error, "Ifpack2::Krylov::getComm: " 00226 "The input matrix A is null. Please call setMatrix() with a nonnull " 00227 "input matrix before calling this method."); 00228 return A_->getComm (); 00229 } 00230 00231 00232 template <class MatrixType> 00233 Teuchos::RCP<const Tpetra::RowMatrix<typename MatrixType::scalar_type,typename MatrixType::local_ordinal_type,typename MatrixType::global_ordinal_type,typename MatrixType::node_type> > 00234 Krylov<MatrixType>::getMatrix () const { 00235 return A_; 00236 } 00237 00238 00239 template <class MatrixType> 00240 Teuchos::RCP<const Tpetra::Map<typename MatrixType::local_ordinal_type,typename MatrixType::global_ordinal_type,typename MatrixType::node_type> > 00241 Krylov<MatrixType>::getDomainMap () const 00242 { 00243 TEUCHOS_TEST_FOR_EXCEPTION( 00244 A_.is_null (), std::runtime_error, "Ifpack2::Krylov::getDomainMap: " 00245 "The input matrix A is null. Please call setMatrix() with a nonnull " 00246 "input matrix before calling this method."); 00247 return A_->getDomainMap (); 00248 } 00249 00250 00251 template <class MatrixType> 00252 Teuchos::RCP<const Tpetra::Map<typename MatrixType::local_ordinal_type,typename MatrixType::global_ordinal_type,typename MatrixType::node_type> > 00253 Krylov<MatrixType>::getRangeMap () const 00254 { 00255 TEUCHOS_TEST_FOR_EXCEPTION( 00256 A_.is_null (), std::runtime_error, "Ifpack2::Krylov::getRangeMap: " 00257 "The input matrix A is null. Please call setMatrix() with a nonnull " 00258 "input matrix before calling this method."); 00259 return A_->getRangeMap (); 00260 } 00261 00262 00263 template <class MatrixType> 00264 bool Krylov<MatrixType>::hasTransposeApply () const { 00265 // FIXME (mfh 17 Jan 2014) apply() does not currently work with mode 00266 // != NO_TRANS, so it's correct to return false here. 00267 return false; 00268 } 00269 00270 00271 template <class MatrixType> 00272 int Krylov<MatrixType>::getNumInitialize () const { 00273 return NumInitialize_; 00274 } 00275 00276 00277 template <class MatrixType> 00278 int Krylov<MatrixType>::getNumCompute () const { 00279 return NumCompute_; 00280 } 00281 00282 00283 template <class MatrixType> 00284 int Krylov<MatrixType>::getNumApply () const { 00285 return NumApply_; 00286 } 00287 00288 00289 template <class MatrixType> 00290 double Krylov<MatrixType>::getInitializeTime () const { 00291 return InitializeTime_; 00292 } 00293 00294 00295 template <class MatrixType> 00296 double Krylov<MatrixType>::getComputeTime () const { 00297 return ComputeTime_; 00298 } 00299 00300 00301 template <class MatrixType> 00302 double Krylov<MatrixType>::getApplyTime () const { 00303 return ApplyTime_; 00304 } 00305 00306 00307 template <class MatrixType> 00308 typename Krylov<MatrixType>::magnitude_type 00309 Krylov<MatrixType>:: 00310 computeCondEst (CondestType CT, 00311 local_ordinal_type MaxIters, 00312 magnitude_type Tol, 00313 const Teuchos::Ptr<const row_matrix_type>& matrix) 00314 { 00315 if (! isComputed ()) { // cannot compute right now 00316 return -STM::one (); 00317 } 00318 // NOTE: this is computing the *local* condest 00319 if (Condest_ == -STM::one ()) { 00320 Condest_ = Ifpack2::Condest (*this, CT, MaxIters, Tol, matrix); 00321 } 00322 return Condest_; 00323 } 00324 00325 00326 template <class MatrixType> 00327 void Krylov<MatrixType>::initialize () 00328 { 00329 using Teuchos::ParameterList; 00330 using Teuchos::RCP; 00331 using Teuchos::rcp; 00332 typedef Tpetra::MultiVector<scalar_type, local_ordinal_type, 00333 global_ordinal_type, node_type> TMV; 00334 typedef Tpetra::Operator<scalar_type, local_ordinal_type, 00335 global_ordinal_type, node_type> TOP; 00336 00337 TEUCHOS_TEST_FOR_EXCEPTION( 00338 A_.is_null (), std::runtime_error, "Ifpack2::Krylov::initialize: " 00339 "The input matrix A is null. Please call setMatrix() with a nonnull " 00340 "input matrix before calling this method."); 00341 00342 // clear any previous allocation 00343 IsInitialized_ = false; 00344 IsComputed_ = false; 00345 00346 Teuchos::Time timer ("initialize"); 00347 { // The body of code to time 00348 Teuchos::TimeMonitor timeMon (timer); 00349 00350 // Belos parameter list 00351 RCP<ParameterList> belosList = rcp (new ParameterList ("GMRES")); 00352 belosList->set ("Maximum Iterations", numIters_); 00353 belosList->set ("Convergence Tolerance", resTol_); 00354 00355 // FIXME (17 Jan 2014) This whole "preconditioner type" thing is 00356 // not how we want Krylov to initialize its inner preconditioner. 00357 // Krylov should be initialized like AdditiveSchwarz: the Factory 00358 // should create it, in order to avoid circular dependencies. 00359 00360 if (PreconditionerType_ == 0) { 00361 // no preconditioner 00362 } 00363 else if (PreconditionerType_==1) { 00364 ifpack2_prec_=rcp (new Relaxation<MatrixType> (A_)); 00365 } 00366 else if (PreconditionerType_==2) { 00367 ifpack2_prec_=rcp (new ILUT<MatrixType> (A_)); 00368 } 00369 else if (PreconditionerType_==3) { 00370 ifpack2_prec_ = rcp (new RILUK<MatrixType> (A_)); 00371 } 00372 else if (PreconditionerType_==4) { 00373 ifpack2_prec_ = rcp (new Chebyshev<MatrixType> (A_)); 00374 } 00375 if (PreconditionerType_>0) { 00376 ifpack2_prec_->initialize(); 00377 ifpack2_prec_->setParameters(precParams_); 00378 } 00379 belosProblem_ = rcp (new Belos::LinearProblem<belos_scalar_type,TMV,TOP> ()); 00380 belosProblem_->setOperator (A_); 00381 00382 if (iterationType_ == "GMRES") { 00383 belosSolver_ = 00384 rcp (new Belos::BlockGmresSolMgr<belos_scalar_type,TMV,TOP> (belosProblem_, belosList)); 00385 } 00386 else { 00387 belosSolver_ = 00388 rcp (new Belos::BlockCGSolMgr<belos_scalar_type,TMV,TOP> (belosProblem_, belosList)); 00389 } 00390 00391 } 00392 IsInitialized_ = true; 00393 ++NumInitialize_; 00394 InitializeTime_ += timer.totalElapsedTime (); 00395 } 00396 00397 00398 template <class MatrixType> 00399 void Krylov<MatrixType>::compute () 00400 { 00401 TEUCHOS_TEST_FOR_EXCEPTION( 00402 A_.is_null (), std::runtime_error, "Ifpack2::Krylov::compute: " 00403 "The input matrix A is null. Please call setMatrix() with a nonnull " 00404 "input matrix before calling this method."); 00405 00406 // Don't time the initialize(); that gets timed separately. 00407 if (! isInitialized ()) { 00408 initialize (); 00409 } 00410 00411 Teuchos::Time timer ("compute"); 00412 { // The body of code to time 00413 Teuchos::TimeMonitor timeMon (timer); 00414 if (PreconditionerType_ > 0) { 00415 ifpack2_prec_->compute (); 00416 belosProblem_->setLeftPrec (ifpack2_prec_); 00417 } 00418 } 00419 IsComputed_ = true; 00420 ++NumCompute_; 00421 ComputeTime_ += timer.totalElapsedTime (); 00422 } 00423 00424 00425 template <class MatrixType> 00426 void Krylov<MatrixType>:: 00427 apply (const Tpetra::MultiVector<typename MatrixType::scalar_type, 00428 typename MatrixType::local_ordinal_type, 00429 typename MatrixType::global_ordinal_type, 00430 typename MatrixType::node_type>& X, 00431 Tpetra::MultiVector<typename MatrixType::scalar_type, 00432 typename MatrixType::local_ordinal_type, 00433 typename MatrixType::global_ordinal_type, 00434 typename MatrixType::node_type>& Y, 00435 Teuchos::ETransp mode, 00436 typename MatrixType::scalar_type alpha, 00437 typename MatrixType::scalar_type beta) const 00438 { 00439 using Teuchos::RCP; 00440 using Teuchos::rcp; 00441 using Teuchos::rcpFromRef; 00442 typedef Tpetra::MultiVector<scalar_type, local_ordinal_type, 00443 global_ordinal_type, node_type> MV; 00444 TEUCHOS_TEST_FOR_EXCEPTION( 00445 ! isComputed (), std::runtime_error, 00446 "Ifpack2::Krylov::apply: You must call compute() before you may call apply()."); 00447 TEUCHOS_TEST_FOR_EXCEPTION( 00448 X.getNumVectors () != Y.getNumVectors (), std::invalid_argument, 00449 "Ifpack2::Krylov::apply: The MultiVector inputs X and Y do not have the " 00450 "same number of columns. X.getNumVectors() = " << X.getNumVectors () 00451 << " != Y.getNumVectors() = " << Y.getNumVectors () << "."); 00452 00453 // Catch unimplemented cases: alpha != 1, beta != 0, mode != NO_TRANS. 00454 TEUCHOS_TEST_FOR_EXCEPTION( 00455 alpha != STS::one (), std::logic_error, 00456 "Ifpack2::Krylov::apply: alpha != 1 has not been implemented."); 00457 TEUCHOS_TEST_FOR_EXCEPTION( 00458 beta != STS::zero (), std::logic_error, 00459 "Ifpack2::Krylov::apply: zero != 0 has not been implemented."); 00460 TEUCHOS_TEST_FOR_EXCEPTION( 00461 mode != Teuchos::NO_TRANS, std::logic_error, 00462 "Ifpack2::Krylov::apply: mode != Teuchos::NO_TRANS has not been implemented."); 00463 00464 Teuchos::Time timer ("apply"); 00465 { // The body of code to time 00466 Teuchos::TimeMonitor timeMon (timer); 00467 00468 // If X and Y are pointing to the same memory location, 00469 // we need to create an auxiliary vector, Xcopy 00470 RCP<const MV> Xcopy; 00471 if (X.getLocalMV ().getValues () == Y.getLocalMV ().getValues ()) { 00472 Xcopy = rcp (new MV (X, Teuchos::Copy)); 00473 } else { 00474 Xcopy = rcpFromRef (X); 00475 } 00476 00477 RCP<MV> Ycopy = rcpFromRef (Y); 00478 if (ZeroStartingSolution_) { 00479 Ycopy->putScalar (STS::zero ()); 00480 } 00481 00482 // Set left and right hand sides for Belos 00483 belosProblem_->setProblem (Ycopy, Xcopy); 00484 belosSolver_->solve (); // solve the linear system 00485 } 00486 ++NumApply_; 00487 ApplyTime_ += timer.totalElapsedTime (); 00488 } 00489 00490 00491 template <class MatrixType> 00492 std::string Krylov<MatrixType>::description () const 00493 { 00494 std::ostringstream os; 00495 00496 // Output is a valid YAML dictionary in flow style. If you don't 00497 // like everything on a single line, you should call describe() 00498 // instead. 00499 os << "\"Ifpack2::Krylov\": {"; 00500 if (this->getObjectLabel () != "") { 00501 os << "Label: \"" << this->getObjectLabel () << "\", "; 00502 } 00503 os << "Initialized: " << (isInitialized () ? "true" : "false") << ", " 00504 << "Computed: " << (isComputed () ? "true" : "false") << ", "; 00505 00506 if (A_.is_null ()) { 00507 os << "Matrix: null"; 00508 } 00509 else { 00510 os << "Matrix: not null" 00511 << ", Global matrix dimensions: [" 00512 << A_->getGlobalNumRows () << ", " << A_->getGlobalNumCols () << "]"; 00513 } 00514 00515 os << "}"; 00516 return os.str (); 00517 } 00518 00519 00520 template <class MatrixType> 00521 void Krylov<MatrixType>:: 00522 describe (Teuchos::FancyOStream &out, 00523 const Teuchos::EVerbosityLevel verbLevel) const 00524 { 00525 using std::endl; 00526 using std::setw; 00527 using Teuchos::VERB_DEFAULT; 00528 using Teuchos::VERB_NONE; 00529 using Teuchos::VERB_LOW; 00530 using Teuchos::VERB_MEDIUM; 00531 using Teuchos::VERB_HIGH; 00532 using Teuchos::VERB_EXTREME; 00533 00534 const Teuchos::EVerbosityLevel vl = 00535 (verbLevel == VERB_DEFAULT) ? VERB_LOW : verbLevel; 00536 00537 if (vl != VERB_NONE) { 00538 // describe() always starts with a tab by convention. 00539 Teuchos::OSTab tab0 (out); 00540 out << "\"Ifpack2::Krylov\":"; 00541 00542 Teuchos::OSTab tab1 (out); 00543 if (this->getObjectLabel () != "") { 00544 out << "Label: " << this->getObjectLabel () << endl; 00545 } 00546 out << "Initialized: " << (isInitialized () ? "true" : "false") << endl 00547 << "Computed: " << (isComputed () ? "true" : "false") << endl 00548 << "Global number of rows: " << A_->getGlobalNumRows () << endl 00549 << "Global number of columns: " << A_->getGlobalNumCols () << endl 00550 << "Matrix:"; 00551 if (A_.is_null ()) { 00552 out << " null" << endl; 00553 } else { 00554 A_->describe (out, vl); 00555 } 00556 } 00557 } 00558 00559 } // namespace Ifpack2 00560 00561 // FIXME (mfh 16 Sep 2014) We should really only use RowMatrix here! 00562 // There's no need to instantiate for CrsMatrix too. All Ifpack2 00563 // preconditioners can and should do dynamic casts if they need a type 00564 // more specific than RowMatrix. 00565 // 00566 // In fact, Krylov really doesn't _need_ the RowMatrix methods; it 00567 // could very well just rely on the Operator interface. initialize() 00568 // need only check whether the domain and range Maps have changed 00569 // (which would necessitate reinitializing the Krylov solver). 00570 00571 #define IFPACK2_KRYLOV_INSTANT(S,LO,GO,N) \ 00572 template class Ifpack2::Krylov< Tpetra::RowMatrix<S, LO, GO, N> >; \ 00573 template class Ifpack2::Krylov< Tpetra::CrsMatrix<S, LO, GO, N> >; 00574 00575 #endif /* IFPACK2_KRYLOV_DEF_HPP */
1.7.6.1