|
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_ADDITIVESCHWARZ_DEF_HPP 00044 #define IFPACK2_ADDITIVESCHWARZ_DEF_HPP 00045 00046 #include "Ifpack2_AdditiveSchwarz_decl.hpp" 00047 00048 // AdditiveSchwarz uses OneLevelFactory to create a default inner 00049 // preconditioner. 00050 // 00051 // FIXME (mfh 13 Dec 2013) For some inexplicable reason, I have to 00052 // include the _decl and _def headers separately here; including just 00053 // Ifpack2_Details_OneLevelFactory.hpp doesn't work. It probably has 00054 // something to do with ETI, but I don't fully understand what. 00055 #include "Ifpack2_Details_OneLevelFactory_decl.hpp" 00056 #include "Ifpack2_Details_OneLevelFactory_def.hpp" 00057 00058 #if defined(HAVE_IFPACK2_XPETRA) && defined(HAVE_IFPACK2_ZOLTAN2) 00059 #include "Xpetra_RowMatrix.hpp" 00060 #include "Xpetra_TpetraRowMatrix.hpp" 00061 #include "Zoltan2_XpetraRowMatrixAdapter.hpp" 00062 #include "Zoltan2_OrderingProblem.hpp" 00063 #include "Zoltan2_OrderingSolution.hpp" 00064 #endif 00065 00066 #if defined(HAVE_IFPACK2_EXPERIMENTAL) && defined(HAVE_IFPACK2_SUPPORTGRAPH) 00067 #include "Ifpack2_SupportGraph_decl.hpp" 00068 #endif 00069 00070 #include "Ifpack2_Condest.hpp" 00071 #include "Ifpack2_Details_CanChangeMatrix.hpp" 00072 #include "Ifpack2_LocalFilter_def.hpp" 00073 #include "Ifpack2_OverlappingRowMatrix_def.hpp" 00074 #include "Ifpack2_Parameters.hpp" 00075 #include "Ifpack2_ReorderFilter_def.hpp" 00076 #include "Ifpack2_SingletonFilter_def.hpp" 00077 00078 #ifdef HAVE_MPI 00079 #include "Teuchos_DefaultMpiComm.hpp" 00080 #endif 00081 00082 #include <locale> // std::toupper 00083 00084 namespace Ifpack2 { 00085 00086 namespace Details { 00087 00103 template<class PrecType> 00104 class OneLevelPreconditionerNamer { 00105 public: 00107 static std::string name () { 00108 // The default implementation returns an invalid preconditioner 00109 // name. This ensures that AdditiveSchwarz won't try to create a 00110 // preconditioner it doesn't know how to create. This is better 00111 // than providing a valid default that is a different class than 00112 // the user expects. 00113 return "INVALID"; 00114 } 00115 }; 00116 00117 // 00118 // Partial specialization for Ifpack2::Preconditioner. 00119 // It picks a reasonable default subdomain solver. 00120 // 00121 00122 template<class S, class LO, class GO, class NT> 00123 class OneLevelPreconditionerNamer< ::Ifpack2::Preconditioner<S, LO, GO, NT> > { 00124 public: 00125 static std::string name () { 00126 // The default inner preconditioner is "ILUT", for backwards 00127 // compatibility with the original AdditiveSchwarz implementation. 00128 return "ILUT"; 00129 } 00130 }; 00131 00132 // 00133 // Partial specializations for each single-level preconditioner. 00134 // 00135 00136 template<class MatrixType> 00137 class OneLevelPreconditionerNamer< ::Ifpack2::Chebyshev<MatrixType> > { 00138 public: 00139 static std::string name () { 00140 return "CHEBYSHEV"; 00141 } 00142 }; 00143 00144 template<class MatrixType> 00145 class OneLevelPreconditionerNamer< ::Ifpack2::Details::DenseSolver<MatrixType> > { 00146 public: 00147 static std::string name () { 00148 return "DENSE"; 00149 } 00150 }; 00151 00152 #ifdef HAVE_IFPACK2_AMESOS2 00153 template<class MatrixType> 00154 class OneLevelPreconditionerNamer< ::Ifpack2::Details::Amesos2Wrapper<MatrixType> > { 00155 public: 00156 static std::string name () { 00157 return "AMESOS2"; 00158 } 00159 }; 00160 #endif // HAVE_IFPACK2_AMESOS2 00161 00162 template<class MatrixType> 00163 class OneLevelPreconditionerNamer< ::Ifpack2::Diagonal<MatrixType> > { 00164 public: 00165 static std::string name () { 00166 return "DIAGONAL"; 00167 } 00168 }; 00169 00170 template<class MatrixType> 00171 class OneLevelPreconditionerNamer< ::Ifpack2::ILUT<MatrixType> > { 00172 public: 00173 static std::string name () { 00174 return "ILUT"; 00175 } 00176 }; 00177 00178 template<class MatrixType> 00179 class OneLevelPreconditionerNamer< ::Ifpack2::Relaxation<MatrixType> > { 00180 public: 00181 static std::string name () { 00182 return "RELAXATION"; 00183 } 00184 }; 00185 00186 template<class MatrixType> 00187 class OneLevelPreconditionerNamer< ::Ifpack2::RILUK<MatrixType> > { 00188 public: 00189 static std::string name () { 00190 return "RILUK"; 00191 } 00192 }; 00193 00194 template<class MatrixType> 00195 class OneLevelPreconditionerNamer< ::Ifpack2::Krylov<MatrixType> > { 00196 public: 00197 static std::string name () { 00198 return "KRYLOV"; 00199 } 00200 }; 00201 00202 template<class MatrixType> 00203 class OneLevelPreconditionerNamer< ::Ifpack2::IdentitySolver<MatrixType> > { 00204 public: 00205 static std::string name () { 00206 return "IDENTITY"; 00207 } 00208 }; 00209 00210 } // namespace Details 00211 00212 00213 template<class MatrixType, class LocalInverseType> 00214 bool 00215 AdditiveSchwarz<MatrixType, LocalInverseType>::hasInnerPrecName () const 00216 { 00217 const char* options[4] = { 00218 "inner preconditioner name", 00219 "subdomain solver name", 00220 "schwarz: inner preconditioner name", 00221 "schwarz: subdomain solver name" 00222 }; 00223 const int numOptions = 4; 00224 bool match = false; 00225 for (int k = 0; k < numOptions && ! match; ++k) { 00226 if (List_.isParameter (options[k])) { 00227 return true; 00228 } 00229 } 00230 return false; 00231 } 00232 00233 00234 template<class MatrixType, class LocalInverseType> 00235 void 00236 AdditiveSchwarz<MatrixType, LocalInverseType>::removeInnerPrecName () 00237 { 00238 const char* options[4] = { 00239 "inner preconditioner name", 00240 "subdomain solver name", 00241 "schwarz: inner preconditioner name", 00242 "schwarz: subdomain solver name" 00243 }; 00244 const int numOptions = 4; 00245 for (int k = 0; k < numOptions; ++k) { 00246 List_.remove (options[k], false); 00247 } 00248 } 00249 00250 00251 00252 00253 00254 template<class MatrixType, class LocalInverseType> 00255 std::string 00256 AdditiveSchwarz<MatrixType, LocalInverseType>::innerPrecName () const 00257 { 00258 const char* options[4] = { 00259 "inner preconditioner name", 00260 "subdomain solver name", 00261 "schwarz: inner preconditioner name", 00262 "schwarz: subdomain solver name" 00263 }; 00264 const int numOptions = 4; 00265 std::string newName; 00266 bool match = false; 00267 00268 // As soon as one parameter option matches, ignore all others. 00269 for (int k = 0; k < numOptions && ! match; ++k) { 00270 if (List_.isParameter (options[k])) { 00271 // try-catch block protects against incorrect type errors. 00272 // 00273 // FIXME (mfh 04 Jan 2013) We should instead catch and report 00274 // type errors. 00275 try { 00276 newName = List_.get<std::string> (options[k]); 00277 match = true; 00278 } catch (...) {} 00279 } 00280 } 00281 return match ? newName : defaultInnerPrecName (); 00282 } 00283 00284 00285 template<class MatrixType, class LocalInverseType> 00286 void 00287 AdditiveSchwarz<MatrixType, LocalInverseType>::removeInnerPrecParams () 00288 { 00289 const char* options[4] = { 00290 "inner preconditioner parameters", 00291 "subdomain solver parameters", 00292 "schwarz: inner preconditioner parameters", 00293 "schwarz: subdomain solver parameters" 00294 }; 00295 const int numOptions = 4; 00296 00297 // As soon as one parameter option matches, ignore all others. 00298 for (int k = 0; k < numOptions; ++k) { 00299 List_.remove (options[k], false); 00300 } 00301 } 00302 00303 00304 template<class MatrixType, class LocalInverseType> 00305 std::pair<Teuchos::ParameterList, bool> 00306 AdditiveSchwarz<MatrixType, LocalInverseType>::innerPrecParams () const 00307 { 00308 const char* options[4] = { 00309 "inner preconditioner parameters", 00310 "subdomain solver parameters", 00311 "schwarz: inner preconditioner parameters", 00312 "schwarz: subdomain solver parameters" 00313 }; 00314 const int numOptions = 4; 00315 Teuchos::ParameterList params; 00316 00317 // As soon as one parameter option matches, ignore all others. 00318 bool match = false; 00319 for (int k = 0; k < numOptions && ! match; ++k) { 00320 if (List_.isSublist (options[k])) { 00321 params = List_.sublist (options[k]); 00322 match = true; 00323 } 00324 } 00325 // Default is an empty list of parameters. 00326 return std::make_pair (params, match); 00327 } 00328 00329 00330 template<class MatrixType, class LocalInverseType> 00331 std::string 00332 AdditiveSchwarz<MatrixType, LocalInverseType>::defaultInnerPrecName () 00333 { 00334 // FIXME (mfh 14 Dec 2013) We want to get rid of the 00335 // LocalInverseType template parameter. Soon, we will add an "inner 00336 // preconditioner" string parameter to the input ParameterList. For 00337 // now, we map statically from LocalInverseType to its string name, 00338 // and use the string name to create the inner preconditioner. 00339 return Details::OneLevelPreconditionerNamer<LocalInverseType>::name (); 00340 } 00341 00342 00343 template<class MatrixType, class LocalInverseType> 00344 AdditiveSchwarz<MatrixType, LocalInverseType>:: 00345 AdditiveSchwarz (const Teuchos::RCP<const row_matrix_type>& A) : 00346 Matrix_ (A), 00347 IsInitialized_ (false), 00348 IsComputed_ (false), 00349 IsOverlapping_ (false), 00350 OverlapLevel_ (0), 00351 CombineMode_ (Tpetra::ZERO), 00352 Condest_ (-Teuchos::ScalarTraits<magnitude_type>::one ()), 00353 ComputeCondest_ (true), 00354 UseReordering_ (false), 00355 ReorderingAlgorithm_ ("none"), 00356 UseSubdomain_ (false), 00357 FilterSingletons_ (false), 00358 NumInitialize_ (0), 00359 NumCompute_ (0), 00360 NumApply_ (0), 00361 InitializeTime_ (0.0), 00362 ComputeTime_ (0.0), 00363 ApplyTime_ (0.0) 00364 { 00365 Teuchos::ParameterList plist; 00366 setParameters (plist); // Set parameters to default values 00367 } 00368 00369 template<class MatrixType, class LocalInverseType> 00370 AdditiveSchwarz<MatrixType, LocalInverseType>:: 00371 AdditiveSchwarz (const Teuchos::RCP<const row_matrix_type>& A, 00372 const int overlapLevel) : 00373 Matrix_ (A), 00374 IsInitialized_ (false), 00375 IsComputed_ (false), 00376 IsOverlapping_ (false), 00377 OverlapLevel_ (overlapLevel), 00378 CombineMode_ (Tpetra::ZERO), 00379 Condest_ (-Teuchos::ScalarTraits<magnitude_type>::one ()), 00380 ComputeCondest_ (true), 00381 UseReordering_ (false), 00382 ReorderingAlgorithm_ ("none"), 00383 UseSubdomain_ (false), 00384 FilterSingletons_ (false), 00385 NumInitialize_ (0), 00386 NumCompute_ (0), 00387 NumApply_ (0), 00388 InitializeTime_ (0.0), 00389 ComputeTime_ (0.0), 00390 ApplyTime_ (0.0) 00391 { 00392 Teuchos::ParameterList plist; 00393 setParameters (plist); // Set parameters to default values 00394 } 00395 00396 00397 template<class MatrixType,class LocalInverseType> 00398 AdditiveSchwarz<MatrixType,LocalInverseType>::~AdditiveSchwarz () {} 00399 00400 00401 template<class MatrixType,class LocalInverseType> 00402 Teuchos::RCP<const Tpetra::Map<typename MatrixType::local_ordinal_type, typename MatrixType::global_ordinal_type, typename MatrixType::node_type > > 00403 AdditiveSchwarz<MatrixType,LocalInverseType>::getDomainMap() const 00404 { 00405 TEUCHOS_TEST_FOR_EXCEPTION( 00406 Matrix_.is_null (), std::runtime_error, "Ifpack2::AdditiveSchwarz::" 00407 "getDomainMap: The matrix to precondition is null. You must either pass " 00408 "a nonnull matrix to the constructor, or call setMatrix() with a nonnull " 00409 "input, before you may call this method."); 00410 return Matrix_->getDomainMap (); 00411 } 00412 00413 00414 template<class MatrixType,class LocalInverseType> 00415 Teuchos::RCP<const Tpetra::Map<typename MatrixType::local_ordinal_type, typename MatrixType::global_ordinal_type, typename MatrixType::node_type> > 00416 AdditiveSchwarz<MatrixType,LocalInverseType>::getRangeMap () const 00417 { 00418 TEUCHOS_TEST_FOR_EXCEPTION( 00419 Matrix_.is_null (), std::runtime_error, "Ifpack2::AdditiveSchwarz::" 00420 "getRangeMap: The matrix to precondition is null. You must either pass " 00421 "a nonnull matrix to the constructor, or call setMatrix() with a nonnull " 00422 "input, before you may call this method."); 00423 return Matrix_->getRangeMap (); 00424 } 00425 00426 00427 template<class MatrixType,class LocalInverseType> 00428 Teuchos::RCP<const Tpetra::RowMatrix<typename MatrixType::scalar_type, typename MatrixType::local_ordinal_type, typename MatrixType::global_ordinal_type, typename MatrixType::node_type> > AdditiveSchwarz<MatrixType,LocalInverseType>::getMatrix() const 00429 { 00430 return Matrix_; 00431 } 00432 00433 00434 template<class MatrixType,class LocalInverseType> 00435 void 00436 AdditiveSchwarz<MatrixType,LocalInverseType>:: 00437 apply (const Tpetra::MultiVector<scalar_type,local_ordinal_type,global_ordinal_type,node_type> &X, 00438 Tpetra::MultiVector<scalar_type,local_ordinal_type,global_ordinal_type,node_type> &Y, 00439 Teuchos::ETransp mode, 00440 scalar_type alpha, 00441 scalar_type beta) const 00442 { 00443 using Teuchos::Time; 00444 using Teuchos::TimeMonitor; 00445 using Teuchos::RCP; 00446 using Teuchos::rcp; 00447 00448 const std::string timerName ("Ifpack2::AdditiveSchwarz::apply"); 00449 RCP<Time> timer = TimeMonitor::lookupCounter (timerName); 00450 if (timer.is_null ()) { 00451 timer = TimeMonitor::getNewCounter (timerName); 00452 } 00453 00454 { // Start timing here. 00455 TimeMonitor timeMon (*timer); 00456 00457 const scalar_type ZERO = Teuchos::ScalarTraits<scalar_type>::zero (); 00458 const scalar_type ONE = Teuchos::ScalarTraits<scalar_type>::one (); 00459 00460 TEUCHOS_TEST_FOR_EXCEPTION( 00461 ! IsComputed_, std::runtime_error, 00462 "Ifpack2::AdditiveSchwarz::apply: " 00463 "isComputed() must be true before you may call apply()."); 00464 TEUCHOS_TEST_FOR_EXCEPTION( 00465 Matrix_.is_null (), std::logic_error, "Ifpack2::AdditiveSchwarz::apply: " 00466 "The input matrix A is null, but the preconditioner says that it has " 00467 "been computed (isComputed() is true). This should never happen, since " 00468 "setMatrix() should always mark the preconditioner as not computed if " 00469 "its argument is null. " 00470 "Please report this bug to the Ifpack2 developers."); 00471 TEUCHOS_TEST_FOR_EXCEPTION( 00472 Inverse_.is_null (), std::runtime_error, 00473 "Ifpack2::AdditiveSchwarz::apply: The subdomain solver is null. " 00474 "This can only happen if you called setInnerPreconditioner() with a null " 00475 "input, after calling initialize() or compute(). If you choose to call " 00476 "setInnerPreconditioner() with a null input, you must then call it with " 00477 "a nonnull input before you may call initialize() or compute()."); 00478 TEUCHOS_TEST_FOR_EXCEPTION( 00479 X.getNumVectors() != Y.getNumVectors(), std::invalid_argument, 00480 "Ifpack2::AdditiveSchwarz::apply: " 00481 "X and Y must have the same number of columns. X has " 00482 << X.getNumVectors() << " columns, but Y has " << Y.getNumVectors() << "."); 00483 TEUCHOS_TEST_FOR_EXCEPTION( 00484 alpha != ONE, std::logic_error, 00485 "Ifpack2::AdditiveSchwarz::apply: Not implemented for alpha != 1."); 00486 TEUCHOS_TEST_FOR_EXCEPTION( 00487 beta != ZERO, std::logic_error, 00488 "Ifpack2::AdditiveSchwarz::apply: Not implemented for beta != 0."); 00489 00490 const size_t numVectors = X.getNumVectors (); 00491 00492 RCP<MV> OverlappingX,OverlappingY; 00493 00494 if (IsOverlapping_) { 00495 TEUCHOS_TEST_FOR_EXCEPTION( 00496 OverlappingMatrix_.is_null (), std::logic_error, 00497 "Ifpack2::AdditiveSchwarz::apply: The overlapping matrix is null. " 00498 "This should never happen if IsOverlapping_ is true. " 00499 "Please report this bug to the Ifpack2 developers."); 00500 00501 // Setup if we're overlapping 00502 // 00503 // MV's constructor fills with zeros. 00504 OverlappingX = rcp (new MV (OverlappingMatrix_->getRowMap (), numVectors)); 00505 OverlappingY = rcp (new MV (OverlappingMatrix_->getRowMap (), numVectors)); 00506 OverlappingMatrix_->importMultiVector (X, *OverlappingX, Tpetra::INSERT); 00507 // FIXME from Ifpack1: Will not work with non-zero starting solutions. 00508 } 00509 else { 00510 TEUCHOS_TEST_FOR_EXCEPTION( 00511 localMap_.is_null (), std::logic_error, 00512 "Ifpack2::AdditiveSchwarz::apply: localMap_ is null."); 00513 00514 // MV's constructor fills with zeros. 00515 // 00516 // localMap_ has the same number of indices on each process that 00517 // Matrix_->getRowMap() does on that process. Thus, we can do 00518 // the Import step without creating a new MV, just by viewing 00519 // OverlappingX using Matrix_->getRowMap (). 00520 OverlappingX = rcp (new MV (localMap_, numVectors)); 00521 OverlappingY = rcp (new MV (localMap_, numVectors)); 00522 00523 RCP<MV> globalOverlappingX = 00524 OverlappingX->offsetViewNonConst (Matrix_->getRowMap (), 0); 00525 00526 // Create Import object on demand, if necessary. 00527 if (DistributedImporter_.is_null ()) { 00528 // FIXME (mfh 15 Apr 2014) Why can't we just ask the Matrix 00529 // for its Import object? Of course a general RowMatrix might 00530 // not necessarily have one. 00531 DistributedImporter_ = 00532 rcp (new import_type (Matrix_->getRowMap (), 00533 Matrix_->getDomainMap ())); 00534 } 00535 globalOverlappingX->doImport (X, *DistributedImporter_, Tpetra::INSERT); 00536 } 00537 00538 if (FilterSingletons_) { 00539 // process singleton filter 00540 MV ReducedX (SingletonMatrix_->getRowMap (), numVectors); 00541 MV ReducedY (SingletonMatrix_->getRowMap (), numVectors); 00542 SingletonMatrix_->SolveSingletons (*OverlappingX, *OverlappingY); 00543 SingletonMatrix_->CreateReducedRHS (*OverlappingY, *OverlappingX, ReducedX); 00544 00545 // process reordering 00546 if (! UseReordering_) { 00547 Inverse_->apply (ReducedX, ReducedY); 00548 } 00549 else { 00550 MV ReorderedX (ReducedX, Teuchos::Copy); 00551 MV ReorderedY (ReducedY, Teuchos::Copy); 00552 ReorderedLocalizedMatrix_->permuteOriginalToReordered (ReducedX, ReorderedX); 00553 Inverse_->apply (ReorderedX, ReorderedY); 00554 ReorderedLocalizedMatrix_->permuteReorderedToOriginal (ReorderedY, ReducedY); 00555 } 00556 00557 // finish up with singletons 00558 SingletonMatrix_->UpdateLHS (ReducedY, *OverlappingY); 00559 } 00560 else { 00561 00562 // process reordering 00563 if (! UseReordering_) { 00564 Inverse_->apply (*OverlappingX, *OverlappingY); 00565 } 00566 else { 00567 MV ReorderedX (*OverlappingX, Teuchos::Copy); 00568 MV ReorderedY (*OverlappingY, Teuchos::Copy); 00569 ReorderedLocalizedMatrix_->permuteOriginalToReordered (*OverlappingX, ReorderedX); 00570 Inverse_->apply (ReorderedX, ReorderedY); 00571 ReorderedLocalizedMatrix_->permuteReorderedToOriginal (ReorderedY, *OverlappingY); 00572 } 00573 } 00574 00575 if (IsOverlapping_) { 00576 OverlappingMatrix_->exportMultiVector (*OverlappingY, Y, CombineMode_); 00577 } 00578 else { 00579 // mfh 16 Apr 2014: Make a view of Y with the same Map as 00580 // OverlappingY, so that we can copy OverlappingY into Y. This 00581 // replaces code that iterates over all entries of OverlappingY, 00582 // copying them one at a time into Y. That code assumed that 00583 // the rows of Y and the rows of OverlappingY have the same 00584 // global indices in the same order; see Bug 5992. 00585 RCP<MV> Y_view = Y.offsetViewNonConst (OverlappingY->getMap (), 0); 00586 Tpetra::deep_copy (*Y_view, *OverlappingY); 00587 } 00588 } // Stop timing here. 00589 00590 ++NumApply_; 00591 00592 // timer->totalElapsedTime() returns the total time over all timer 00593 // calls. Thus, we use = instead of +=. 00594 ApplyTime_ = timer->totalElapsedTime (); 00595 } 00596 00597 00598 template<class MatrixType,class LocalInverseType> 00599 void AdditiveSchwarz<MatrixType,LocalInverseType>:: 00600 setParameters (const Teuchos::ParameterList& plist) 00601 { 00602 // mfh 18 Nov 2013: Ifpack2's setParameters() method passes in the 00603 // input list as const. This means that we have to copy it before 00604 // validation or passing into setParameterList(). 00605 List_ = plist; 00606 this->setParameterList (Teuchos::rcpFromRef (List_)); 00607 } 00608 00609 00610 00611 template<class MatrixType,class LocalInverseType> 00612 void AdditiveSchwarz<MatrixType,LocalInverseType>:: 00613 setParameterList (const Teuchos::RCP<Teuchos::ParameterList>& plist) 00614 { 00615 using Tpetra::CombineMode; 00616 using Teuchos::getIntegralValue; 00617 using Teuchos::ParameterEntry; 00618 using Teuchos::ParameterEntryValidator; 00619 using Teuchos::RCP; 00620 using Teuchos::rcp_dynamic_cast; 00621 using Teuchos::StringToIntegralParameterEntryValidator; 00622 00623 if (plist.is_null ()) { 00624 // Assume that the user meant to set default parameters by passing 00625 // in an empty list. 00626 this->setParameterList (Teuchos::parameterList ()); 00627 } 00628 // At this point, plist should be nonnull. 00629 TEUCHOS_TEST_FOR_EXCEPTION( 00630 plist.is_null (), std::logic_error, "Ifpack2::AdditiveSchwarz::" 00631 "setParameterList: plist is null. This should never happen, since the " 00632 "method should have replaced a null input list with a nonnull empty list " 00633 "by this point. Please report this bug to the Ifpack2 developers."); 00634 00635 // try { 00636 // List_.validateParameters (* getValidParameters ()); 00637 // } 00638 // catch (std::exception& e) { 00639 // std::cerr << "Ifpack2::AdditiveSchwarz::setParameterList: Validation failed with the following error message: " << e.what () << std::endl; 00640 // throw e; 00641 // } 00642 00643 // mfh 18 Nov 2013: Supplying the current value as the default value 00644 // when calling ParameterList::get() ensures "delta" behavior when 00645 // users pass in new parameters: any unspecified parameters in the 00646 // new list retain their values in the old list. This preserves 00647 // backwards compatiblity with this class' previous behavior. Note 00648 // that validateParametersAndSetDefaults() would have different 00649 // behavior: any parameters not in the new list would get default 00650 // values, which could be different than their values in the 00651 // original list. 00652 00653 ComputeCondest_ = plist->get ("schwarz: compute condest", ComputeCondest_); 00654 00655 bool gotCombineMode = false; 00656 try { 00657 CombineMode_ = getIntegralValue<Tpetra::CombineMode> (List_, "schwarz: combine mode"); 00658 gotCombineMode = true; 00659 } 00660 catch (Teuchos::Exceptions::InvalidParameterName&) { 00661 // The caller didn't provide that parameter. Just keep the 00662 // existing value of CombineMode_. 00663 gotCombineMode = true; 00664 } 00665 catch (Teuchos::Exceptions::InvalidParameterType&) { 00666 // The user perhaps supplied it as an Tpetra::CombineMode enum 00667 // value. Let's try again (below). If it doesn't succeed, we 00668 // know that the type is wrong, so we can let it throw whatever 00669 // exception it would throw. 00670 } 00671 // Try to get the combine mode as an integer. 00672 if (! gotCombineMode) { 00673 try { 00674 CombineMode_ = plist->get ("schwarz: combine mode", CombineMode_); 00675 gotCombineMode = true; 00676 } 00677 catch (Teuchos::Exceptions::InvalidParameterType&) {} 00678 } 00679 // Try to get the combine mode as a string. If this works, use the 00680 // validator to convert to int. This is painful, but necessary in 00681 // order to do validation, since the input list doesn't come with a 00682 // validator. 00683 if (! gotCombineMode) { 00684 const ParameterEntry& validEntry = 00685 getValidParameters ()->getEntry ("schwarz: combine mode"); 00686 RCP<const ParameterEntryValidator> v = validEntry.validator (); 00687 typedef StringToIntegralParameterEntryValidator<CombineMode> vs2e_type; 00688 RCP<const vs2e_type> vs2e = rcp_dynamic_cast<const vs2e_type> (v, true); 00689 00690 const ParameterEntry& inputEntry = plist->getEntry ("schwarz: combine mode"); 00691 CombineMode_ = vs2e->getIntegralValue (inputEntry, "schwarz: combine mode"); 00692 gotCombineMode = true; 00693 } 00694 (void) gotCombineMode; // forestall "set but not used" compiler warning 00695 00696 OverlapLevel_ = plist->get ("schwarz: overlap level", OverlapLevel_); 00697 00698 // We set IsOverlapping_ in initialize(), once we know that Matrix_ is nonnull. 00699 00700 // Will we be doing reordering? Unlike Ifpack, we'll use a 00701 // "schwarz: reordering list" to give to Zoltan2. 00702 UseReordering_ = plist->get ("schwarz: use reordering", UseReordering_); 00703 00704 #if !defined(HAVE_IFPACK2_XPETRA) || !defined(HAVE_IFPACK2_ZOLTAN2) 00705 TEUCHOS_TEST_FOR_EXCEPTION( 00706 UseReordering_, std::invalid_argument, "Ifpack2::AdditiveSchwarz::" 00707 "setParameters: You specified \"schwarz: use reordering\" = true. " 00708 "This is only valid when Trilinos was built with Ifpack2, Xpetra, and " 00709 "Zoltan2 enabled. Either Xpetra or Zoltan2 was not enabled in your build " 00710 "of Trilinos."); 00711 #endif 00712 00713 // FIXME (mfh 18 Nov 2013) Now would be a good time to validate the 00714 // "schwarz: reordering list" parameter list. Currently, that list 00715 // gets extracted in setup(). 00716 00717 // Subdomain check 00718 if (plist->isParameter ("schwarz: subdomain id") && 00719 plist->get ("schwarz: subdomain id", -1) > 0) { 00720 UseSubdomain_ = true; 00721 } 00722 TEUCHOS_TEST_FOR_EXCEPTION( 00723 UseSubdomain_, std::logic_error, "Ifpack2::AdditiveSchwarz::" 00724 "setParameters: You specified the \"schwarz: subdomain id\" parameter, " 00725 "with a value other than -1. This parameter is not yet supported."); 00726 00727 // if true, filter singletons. NOTE: the filtered matrix can still have 00728 // singletons! A simple example: upper triangular matrix, if I remove 00729 // the lower node, I still get a matrix with a singleton! However, filter 00730 // singletons should help for PDE problems with Dirichlet BCs. 00731 FilterSingletons_ = plist->get ("schwarz: filter singletons", FilterSingletons_); 00732 00733 // If the inner solver doesn't exist yet, don't create it. 00734 // initialize() creates it. 00735 // 00736 // If the inner solver _does_ exist, there are three cases, 00737 // depending on what the user put in the input ParameterList. 00738 // 00739 // 1. The user did /not/ provide a parameter specifying the inner 00740 // solver's type, nor did the user specify a sublist of 00741 // parameters for the inner solver 00742 // 2. The user did /not/ provide a parameter specifying the inner 00743 // solver's type, but /did/ specify a sublist of parameters for 00744 // the inner solver 00745 // 3. The user provided a parameter specifying the inner solver's 00746 // type (it does not matter in this case whether the user gave 00747 // a sublist of parameters for the inner solver) 00748 // 00749 // AdditiveSchwarz has "delta" (relative) semantics for setting 00750 // parameters. This means that if the user did not specify the 00751 // inner solver's type, we presume that the type has not changed. 00752 // Thus, if the inner solver exists, we don't need to recreate it. 00753 // 00754 // In Case 3, if the user bothered to specify the inner solver's 00755 // type, then we must assume it may differ than the current inner 00756 // solver's type. Thus, we have to recreate the inner solver. We 00757 // achieve this here by assigning null to Inverse_; initialize() 00758 // will recreate the solver when it is needed. Our assumption here 00759 // is necessary because Ifpack2::Preconditioner does not have a 00760 // method for querying a preconditioner's "type" (i.e., name) as a 00761 // string. Remember that the user may have previously set an 00762 // arbitrary inner solver by calling setInnerPreconditioner(). 00763 // 00764 // See note at the end of setInnerPreconditioner(). 00765 00766 if (! Inverse_.is_null ()) { 00767 // "CUSTOM" explicitly indicates that the user called or plans to 00768 // call setInnerPreconditioner. 00769 if (hasInnerPrecName () && innerPrecName () != "CUSTOM") { 00770 // Wipe out the current inner solver. initialize() will 00771 // recreate it with the correct type. 00772 Inverse_ = Teuchos::null; 00773 } 00774 else { 00775 // Extract and apply the sublist of parameters to give to the 00776 // inner solver, if there is such a sublist of parameters. 00777 std::pair<Teuchos::ParameterList, bool> result = innerPrecParams (); 00778 if (result.second) { 00779 Inverse_->setParameters (result.first); 00780 } 00781 } 00782 } 00783 } 00784 00785 00786 00787 template<class MatrixType,class LocalInverseType> 00788 Teuchos::RCP<const Teuchos::ParameterList> 00789 AdditiveSchwarz<MatrixType,LocalInverseType>:: 00790 getValidParameters () const 00791 { 00792 using Teuchos::ParameterList; 00793 using Teuchos::parameterList; 00794 using Teuchos::RCP; 00795 using Teuchos::rcp_const_cast; 00796 00797 if (validParams_.is_null ()) { 00798 const int overlapLevel = 0; 00799 const bool useReordering = false; 00800 const bool computeCondest = false; 00801 const bool filterSingletons = false; 00802 ParameterList reorderingSublist; 00803 reorderingSublist.set ("order_method", std::string ("rcm")); 00804 00805 RCP<ParameterList> plist = parameterList ("Ifpack2::AdditiveSchwarz"); 00806 00807 Tpetra::setCombineModeParameter (*plist, "schwarz: combine mode"); 00808 plist->set ("schwarz: overlap level", overlapLevel); 00809 plist->set ("schwarz: use reordering", useReordering); 00810 plist->set ("schwarz: reordering list", reorderingSublist); 00811 plist->set ("schwarz: compute condest", computeCondest); 00812 plist->set ("schwarz: filter singletons", filterSingletons); 00813 00814 // FIXME (mfh 18 Nov 2013) Get valid parameters from inner solver. 00815 // 00816 // FIXME (mfh 18 Nov 2013) Get valid parameters from Zoltan2, if 00817 // Zoltan2 was enabled in the build. 00818 00819 validParams_ = rcp_const_cast<const ParameterList> (plist); 00820 } 00821 return validParams_; 00822 } 00823 00824 00825 template<class MatrixType,class LocalInverseType> 00826 void AdditiveSchwarz<MatrixType,LocalInverseType>::initialize () 00827 { 00828 using Tpetra::global_size_t; 00829 using Teuchos::RCP; 00830 using Teuchos::rcp; 00831 using Teuchos::SerialComm; 00832 using Teuchos::Time; 00833 using Teuchos::TimeMonitor; 00834 00835 const std::string timerName ("Ifpack2::AdditiveSchwarz::initialize"); 00836 RCP<Time> timer = TimeMonitor::lookupCounter (timerName); 00837 if (timer.is_null ()) { 00838 timer = TimeMonitor::getNewCounter (timerName); 00839 } 00840 00841 { // Start timing here. 00842 TimeMonitor timeMon (*timer); 00843 00844 TEUCHOS_TEST_FOR_EXCEPTION( 00845 Matrix_.is_null (), std::runtime_error, "Ifpack2::AdditiveSchwarz::" 00846 "initialize: The matrix to precondition is null. You must either pass " 00847 "a nonnull matrix to the constructor, or call setMatrix() with a nonnull " 00848 "input, before you may call this method."); 00849 00850 IsInitialized_ = false; 00851 IsComputed_ = false; 00852 Condest_ = -Teuchos::ScalarTraits<magnitude_type>::one (); 00853 00854 RCP<const Teuchos::Comm<int> > comm = Matrix_->getComm (); 00855 RCP<const map_type> rowMap = Matrix_->getRowMap (); 00856 RCP<node_type> node = Matrix_->getNode (); 00857 const global_size_t INVALID = 00858 Teuchos::OrdinalTraits<global_size_t>::invalid (); 00859 00860 // If there's only one process in the matrix's communicator, 00861 // then there's no need to compute overlap. 00862 if (comm->getSize () == 1) { 00863 OverlapLevel_ = 0; 00864 IsOverlapping_ = false; 00865 } else if (OverlapLevel_ != 0) { 00866 IsOverlapping_ = true; 00867 } 00868 00869 if (OverlapLevel_ == 0) { 00870 const global_ordinal_type indexBase = rowMap->getIndexBase (); 00871 RCP<const SerialComm<int> > localComm (new SerialComm<int> ()); 00872 // FIXME (mfh 15 Apr 2014) What if indexBase isn't the least 00873 // global index in the list of GIDs on this process? 00874 localMap_ = 00875 rcp (new map_type (INVALID, rowMap->getNodeNumElements (), 00876 indexBase, localComm, node)); 00877 } 00878 00879 // compute the overlapping matrix if necessary 00880 if (IsOverlapping_) { 00881 if (UseSubdomain_) { 00882 const int sid = List_.get ("subdomain id", -1); 00883 OverlappingMatrix_ = rcp (new OverlappingRowMatrix<row_matrix_type> (Matrix_, OverlapLevel_, sid)); 00884 } else { 00885 OverlappingMatrix_ = rcp (new OverlappingRowMatrix<row_matrix_type> (Matrix_, OverlapLevel_)); 00886 } 00887 } 00888 00889 setup (); // This does a lot of the initialization work. 00890 00891 if (! Inverse_.is_null ()) { 00892 Inverse_->initialize (); // Initialize subdomain solver. 00893 } 00894 00895 } // Stop timing here. 00896 00897 IsInitialized_ = true; 00898 ++NumInitialize_; 00899 00900 // timer->totalElapsedTime() returns the total time over all timer 00901 // calls. Thus, we use = instead of +=. 00902 InitializeTime_ = timer->totalElapsedTime (); 00903 } 00904 00905 00906 template<class MatrixType,class LocalInverseType> 00907 bool AdditiveSchwarz<MatrixType,LocalInverseType>::isInitialized () const 00908 { 00909 return IsInitialized_; 00910 } 00911 00912 00913 template<class MatrixType,class LocalInverseType> 00914 void AdditiveSchwarz<MatrixType,LocalInverseType>::compute () 00915 { 00916 using Teuchos::RCP; 00917 using Teuchos::Time; 00918 using Teuchos::TimeMonitor; 00919 00920 if (! IsInitialized_) { 00921 initialize (); 00922 } 00923 00924 TEUCHOS_TEST_FOR_EXCEPTION( 00925 ! isInitialized (), std::logic_error, "Ifpack2::AdditiveSchwarz::compute: " 00926 "The preconditioner is not yet initialized, " 00927 "even though initialize() supposedly has been called. " 00928 "This should never happen. " 00929 "Please report this bug to the Ifpack2 developers."); 00930 00931 TEUCHOS_TEST_FOR_EXCEPTION( 00932 Inverse_.is_null (), std::runtime_error, 00933 "Ifpack2::AdditiveSchwarz::compute: The subdomain solver is null. " 00934 "This can only happen if you called setInnerPreconditioner() with a null " 00935 "input, after calling initialize() or compute(). If you choose to call " 00936 "setInnerPreconditioner() with a null input, you must then call it with a " 00937 "nonnull input before you may call initialize() or compute()."); 00938 00939 const std::string timerName ("Ifpack2::AdditiveSchwarz::compute"); 00940 RCP<Time> timer = TimeMonitor::lookupCounter (timerName); 00941 if (timer.is_null ()) { 00942 timer = TimeMonitor::getNewCounter (timerName); 00943 } 00944 00945 { // Start timing here. 00946 TimeMonitor timeMon (*timer); 00947 00948 IsComputed_ = false; 00949 Condest_ = -Teuchos::ScalarTraits<magnitude_type>::one (); 00950 Inverse_->compute (); 00951 } // Stop timing here. 00952 00953 IsComputed_ = true; 00954 ++NumCompute_; 00955 00956 // timer->totalElapsedTime() returns the total time over all timer 00957 // calls. Thus, we use = instead of +=. 00958 ComputeTime_ = timer->totalElapsedTime (); 00959 } 00960 00961 //============================================================================== 00962 // Returns true if the preconditioner has been successfully computed, false otherwise. 00963 template<class MatrixType,class LocalInverseType> 00964 bool AdditiveSchwarz<MatrixType,LocalInverseType>::isComputed() const 00965 { 00966 return IsComputed_; 00967 } 00968 00969 00970 template<class MatrixType,class LocalInverseType> 00971 typename Teuchos::ScalarTraits<typename MatrixType::scalar_type>::magnitudeType 00972 AdditiveSchwarz<MatrixType,LocalInverseType>:: 00973 computeCondEst (CondestType CT, 00974 local_ordinal_type MaxIters, 00975 magnitude_type Tol, 00976 const Teuchos::Ptr<const Tpetra::RowMatrix<scalar_type,local_ordinal_type,global_ordinal_type,node_type> > &Matrix_in) 00977 { 00978 // The preconditioner must have been computed in order to estimate 00979 // its condition number. 00980 if (! isComputed ()) { 00981 return -Teuchos::ScalarTraits<magnitude_type>::one (); 00982 } 00983 00984 Condest_ = Ifpack2::Condest (*this, CT, MaxIters, Tol, Matrix_in); 00985 return Condest_; 00986 } 00987 00988 00989 template<class MatrixType,class LocalInverseType> 00990 typename Teuchos::ScalarTraits<typename MatrixType::scalar_type>::magnitudeType 00991 AdditiveSchwarz<MatrixType,LocalInverseType>::getCondEst() const 00992 { 00993 return Condest_; 00994 } 00995 00996 00997 template<class MatrixType,class LocalInverseType> 00998 int AdditiveSchwarz<MatrixType,LocalInverseType>::getNumInitialize() const 00999 { 01000 return NumInitialize_; 01001 } 01002 01003 01004 template<class MatrixType,class LocalInverseType> 01005 int AdditiveSchwarz<MatrixType,LocalInverseType>::getNumCompute() const 01006 { 01007 return NumCompute_; 01008 } 01009 01010 01011 template<class MatrixType,class LocalInverseType> 01012 int AdditiveSchwarz<MatrixType,LocalInverseType>::getNumApply() const 01013 { 01014 return NumApply_; 01015 } 01016 01017 01018 template<class MatrixType,class LocalInverseType> 01019 double AdditiveSchwarz<MatrixType,LocalInverseType>::getInitializeTime() const 01020 { 01021 return InitializeTime_; 01022 } 01023 01024 01025 template<class MatrixType,class LocalInverseType> 01026 double AdditiveSchwarz<MatrixType,LocalInverseType>::getComputeTime() const 01027 { 01028 return ComputeTime_; 01029 } 01030 01031 01032 template<class MatrixType,class LocalInverseType> 01033 double AdditiveSchwarz<MatrixType,LocalInverseType>::getApplyTime() const 01034 { 01035 return ApplyTime_; 01036 } 01037 01038 01039 template<class MatrixType,class LocalInverseType> 01040 std::string AdditiveSchwarz<MatrixType,LocalInverseType>::description () const 01041 { 01042 std::ostringstream out; 01043 01044 out << "\"Ifpack2::AdditiveSchwarz\": {"; 01045 if (this->getObjectLabel () != "") { 01046 out << "Label: \"" << this->getObjectLabel () << "\", "; 01047 } 01048 out << "Initialized: " << (isInitialized () ? "true" : "false") 01049 << ", Computed: " << (isComputed () ? "true" : "false") 01050 << ", Overlap level: " << OverlapLevel_ 01051 << ", Subdomain reordering: \"" << ReorderingAlgorithm_ << "\""; 01052 out << ", Combine mode: \""; 01053 if (CombineMode_ == Tpetra::INSERT) { 01054 out << "INSERT"; 01055 } else if (CombineMode_ == Tpetra::ADD) { 01056 out << "ADD"; 01057 } else if (CombineMode_ == Tpetra::REPLACE) { 01058 out << "REPLACE"; 01059 } else if (CombineMode_ == Tpetra::ABSMAX) { 01060 out << "ABSMAX"; 01061 } else if (CombineMode_ == Tpetra::ZERO) { 01062 out << "ZERO"; 01063 } 01064 out << "\""; 01065 if (Matrix_.is_null ()) { 01066 out << ", Matrix: null"; 01067 } 01068 else { 01069 out << ", Global matrix dimensions: [" 01070 << Matrix_->getGlobalNumRows () << ", " 01071 << Matrix_->getGlobalNumCols () << "]"; 01072 } 01073 out << ", Inner solver: "; 01074 if (!Inverse_.is_null ()) 01075 out << "{" << Inverse_->description() << "}"; 01076 else 01077 out << "null"; 01078 01079 out << "}"; 01080 return out.str (); 01081 } 01082 01083 01084 template<class MatrixType,class LocalInverseType> 01085 void 01086 AdditiveSchwarz<MatrixType,LocalInverseType>:: 01087 describe (Teuchos::FancyOStream& out, 01088 const Teuchos::EVerbosityLevel verbLevel) const 01089 { 01090 using Teuchos::OSTab; 01091 using Teuchos::TypeNameTraits; 01092 using std::endl; 01093 01094 const int myRank = Matrix_->getComm ()->getRank (); 01095 const int numProcs = Matrix_->getComm ()->getSize (); 01096 const Teuchos::EVerbosityLevel vl = 01097 (verbLevel == Teuchos::VERB_DEFAULT) ? Teuchos::VERB_LOW : verbLevel; 01098 01099 if (vl > Teuchos::VERB_NONE) { 01100 // describe() starts with a tab, by convention. 01101 OSTab tab0 (out); 01102 if (myRank == 0) { 01103 out << "\"Ifpack2::AdditiveSchwarz\":"; 01104 } 01105 OSTab tab1 (out); 01106 if (myRank == 0) { 01107 out << "MatrixType: " << TypeNameTraits<MatrixType>::name () << endl; 01108 out << "LocalInverseType: " << TypeNameTraits<LocalInverseType>::name () << endl; 01109 if (this->getObjectLabel () != "") { 01110 out << "Label: \"" << this->getObjectLabel () << "\"" << endl; 01111 } 01112 01113 out << "Overlap level: " << OverlapLevel_ << endl 01114 << "Combine mode: \""; 01115 if (CombineMode_ == Tpetra::INSERT) { 01116 out << "INSERT"; 01117 } else if (CombineMode_ == Tpetra::ADD) { 01118 out << "ADD"; 01119 } else if (CombineMode_ == Tpetra::REPLACE) { 01120 out << "REPLACE"; 01121 } else if (CombineMode_ == Tpetra::ABSMAX) { 01122 out << "ABSMAX"; 01123 } else if (CombineMode_ == Tpetra::ZERO) { 01124 out << "ZERO"; 01125 } 01126 out << "\"" << endl 01127 << "Subdomain reordering: \"" << ReorderingAlgorithm_ << "\"" << endl; 01128 } 01129 01130 if (Matrix_.is_null ()) { 01131 if (myRank == 0) { 01132 out << "Matrix: null" << endl; 01133 } 01134 } 01135 else { 01136 if (myRank == 0) { 01137 out << "Matrix:" << endl; 01138 std::flush (out); 01139 } 01140 Matrix_->getComm ()->barrier (); // wait for output to finish 01141 Matrix_->describe (out, Teuchos::VERB_LOW); 01142 } 01143 01144 if (myRank == 0) { 01145 out << "Number of initialize calls: " << getNumInitialize () << endl 01146 << "Number of compute calls: " << getNumCompute () << endl 01147 << "Number of apply calls: " << getNumApply () << endl 01148 << "Total time in seconds for initialize: " << getInitializeTime () << endl 01149 << "Total time in seconds for compute: " << getComputeTime () << endl 01150 << "Total time in seconds for apply: " << getApplyTime () << endl; 01151 } 01152 01153 if (Inverse_.is_null ()) { 01154 if (myRank == 0) { 01155 out << "Subdomain solver: null" << endl; 01156 } 01157 } 01158 else { 01159 if (vl < Teuchos::VERB_EXTREME) { 01160 if (myRank == 0) { 01161 out << "Subdomain solver: not null" << endl; 01162 } 01163 } 01164 else { // vl >= Teuchos::VERB_EXTREME 01165 for (int p = 0; p < numProcs; ++p) { 01166 if (p == myRank) { 01167 out << "Subdomain solver on Process " << myRank << ":"; 01168 if (Inverse_.is_null ()) { 01169 out << "null" << endl; 01170 } else { 01171 out << endl; 01172 Inverse_->describe (out, vl); 01173 } 01174 } 01175 Matrix_->getComm ()->barrier (); 01176 Matrix_->getComm ()->barrier (); 01177 Matrix_->getComm ()->barrier (); // wait for output to finish 01178 } 01179 } 01180 } 01181 01182 Matrix_->getComm ()->barrier (); // wait for output to finish 01183 } 01184 } 01185 01186 01187 template<class MatrixType,class LocalInverseType> 01188 std::ostream& AdditiveSchwarz<MatrixType,LocalInverseType>::print(std::ostream& os) const 01189 { 01190 Teuchos::FancyOStream fos(Teuchos::rcp(&os,false)); 01191 fos.setOutputToRootOnly(0); 01192 describe(fos); 01193 return(os); 01194 } 01195 01196 01197 template<class MatrixType,class LocalInverseType> 01198 int AdditiveSchwarz<MatrixType,LocalInverseType>::getOverlapLevel() const 01199 { 01200 return OverlapLevel_; 01201 } 01202 01203 01204 template<class MatrixType,class LocalInverseType> 01205 void AdditiveSchwarz<MatrixType,LocalInverseType>::setup () 01206 { 01207 #ifdef HAVE_MPI 01208 using Teuchos::MpiComm; 01209 #endif // HAVE_MPI 01210 using Teuchos::ArrayRCP; 01211 using Teuchos::RCP; 01212 using Teuchos::rcp; 01213 using Teuchos::rcp_dynamic_cast; 01214 using Teuchos::rcpFromRef; 01215 01216 #if defined(HAVE_IFPACK2_XPETRA) && defined(HAVE_IFPACK2_ZOLTAN2) 01217 typedef Xpetra::RowMatrix<scalar_type, local_ordinal_type, global_ordinal_type, node_type> XpetraMatrixType; 01218 typedef Xpetra::TpetraRowMatrix<scalar_type, local_ordinal_type, global_ordinal_type, node_type> XpetraTpetraMatrixType; 01219 #endif 01220 01221 TEUCHOS_TEST_FOR_EXCEPTION( 01222 Matrix_.is_null (), std::runtime_error, "Ifpack2::AdditiveSchwarz::" 01223 "initialize: The matrix to precondition is null. You must either pass " 01224 "a nonnull matrix to the constructor, or call setMatrix() with a nonnull " 01225 "input, before you may call this method."); 01226 01227 // Localized version of Matrix_ or OverlappingMatrix_. 01228 RCP<row_matrix_type> LocalizedMatrix; 01229 01230 // The "most current local matrix." At the end of this method, this 01231 // will be handed off to the inner solver. 01232 RCP<row_matrix_type> ActiveMatrix; 01233 01234 // Create localized matrix. 01235 if (! OverlappingMatrix_.is_null ()) { 01236 if (UseSubdomain_) { 01237 // int sid = List_.get("subdomain id",-1); 01238 TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error, 01239 "Ifpack2::AdditiveSchwarz::setup: subdomain code not yet supported."); 01240 // 01241 // FIXME (mfh 18 Nov 2013) btw what's the difference between 01242 // Ifpack_NodeFilter and Ifpack_LocalFilter? The former's 01243 // documentation sounds a lot like what Ifpack2::LocalFilter 01244 // does. 01245 // 01246 //Ifpack2_NodeFilter *tt = new Ifpack2_NodeFilter(OverlappingMatrix_,nodeID); //FIXME 01247 //LocalizedMatrix = Teuchos::rcp(tt); 01248 } 01249 else 01250 LocalizedMatrix = rcp (new LocalFilter<row_matrix_type> (OverlappingMatrix_)); 01251 } 01252 else { 01253 if (UseSubdomain_) { 01254 // int sid = List_.get("subdomain id",-1); 01255 TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error, 01256 "Ifpack2::AdditiveSchwarz::setup: subdomain code not yet supported."); 01257 } 01258 else { 01259 LocalizedMatrix = rcp (new LocalFilter<row_matrix_type> (Matrix_)); 01260 } 01261 } 01262 01263 // Sanity check; I don't trust the logic above to have created LocalizedMatrix. 01264 TEUCHOS_TEST_FOR_EXCEPTION( 01265 LocalizedMatrix.is_null (), std::logic_error, 01266 "Ifpack2::AdditiveSchwarz::setup: LocalizedMatrix is null, after the code " 01267 "that claimed to have created it. This should never be the case. Please " 01268 "report this bug to the Ifpack2 developers."); 01269 01270 // Mark localized matrix as active 01271 ActiveMatrix = LocalizedMatrix; 01272 01273 // Singleton Filtering 01274 if (FilterSingletons_) { 01275 SingletonMatrix_ = rcp (new SingletonFilter<row_matrix_type> (LocalizedMatrix)); 01276 ActiveMatrix = SingletonMatrix_; 01277 } 01278 01279 // Do reordering 01280 if (UseReordering_) { 01281 #if defined(HAVE_IFPACK2_XPETRA) && defined(HAVE_IFPACK2_ZOLTAN2) 01282 // Unlike Ifpack, Zoltan2 does all the dirty work here. 01283 Teuchos::ParameterList zlist = List_.sublist ("schwarz: reordering list"); 01284 01285 // FIXME (mfh 18 Nov 2013) Shouldn't this come from the Zoltan2 sublist? 01286 ReorderingAlgorithm_ = List_.get<std::string> ("order_method", "rcm"); 01287 XpetraTpetraMatrixType XpetraMatrix (ActiveMatrix); 01288 typedef Zoltan2::XpetraRowMatrixAdapter<XpetraMatrixType> z2_adapter_type; 01289 z2_adapter_type Zoltan2Matrix (rcpFromRef (XpetraMatrix)); 01290 typedef Zoltan2::OrderingProblem<z2_adapter_type> ordering_problem_type; 01291 #ifdef HAVE_MPI 01292 // Grab the MPI Communicator and build the ordering problem with that 01293 MPI_Comm myRawComm; 01294 01295 RCP<const MpiComm<int> > mpicomm = 01296 rcp_dynamic_cast<const MpiComm<int> > (ActiveMatrix->getComm ()); 01297 if (mpicomm == Teuchos::null) { 01298 myRawComm = MPI_COMM_SELF; 01299 } else { 01300 myRawComm = * (mpicomm->getRawMpiComm ()); 01301 } 01302 ordering_problem_type MyOrderingProblem (&Zoltan2Matrix, &zlist, myRawComm); 01303 #else 01304 ordering_problem_type MyOrderingProblem (&Zoltan2Matrix, &zlist); 01305 #endif 01306 MyOrderingProblem.solve (); 01307 01308 // Now create the reordered matrix & mark it as active 01309 { 01310 typedef ReorderFilter<row_matrix_type> reorder_filter_type; 01311 typedef Zoltan2::OrderingSolution<global_ordinal_type, 01312 local_ordinal_type> ordering_solution_type; 01313 01314 ordering_solution_type sol (*MyOrderingProblem.getSolution ()); 01315 01316 // perm[i] gives the where OLD index i shows up in the NEW 01317 // ordering. revperm[i] gives the where NEW index i shows 01318 // up in the OLD ordering. Note that perm is actually the 01319 // "inverse permutation," in Zoltan2 terms. 01320 ArrayRCP<local_ordinal_type> perm = sol.getPermutationRCPConst (true); 01321 ArrayRCP<local_ordinal_type> revperm = sol.getPermutationRCPConst (); 01322 01323 ReorderedLocalizedMatrix_ = 01324 rcp (new reorder_filter_type (ActiveMatrix, perm, revperm)); 01325 01326 ActiveMatrix = ReorderedLocalizedMatrix_; 01327 } 01328 #else 01329 // This is a logic_error, not a runtime_error, because 01330 // setParameters() should have excluded this case already. 01331 TEUCHOS_TEST_FOR_EXCEPTION( 01332 true, std::logic_error, "Ifpack2::AdditiveSchwarz::setup: " 01333 "The Zoltan2 and Xpetra packages must be enabled in order " 01334 "to support reordering."); 01335 #endif 01336 } 01337 01338 innerMatrix_ = ActiveMatrix; 01339 01340 TEUCHOS_TEST_FOR_EXCEPTION( 01341 innerMatrix_.is_null (), std::logic_error, "Ifpack2::AdditiveSchwarz::" 01342 "setup: Inner matrix is null right before constructing inner solver. " 01343 "Please report this bug to the Ifpack2 developers."); 01344 01345 // Construct the inner solver if necessary. 01346 if (Inverse_.is_null ()) { 01347 const std::string innerName = innerPrecName (); 01348 TEUCHOS_TEST_FOR_EXCEPTION( 01349 innerName == "INVALID", std::logic_error, 01350 "Ifpack2::AdditiveSchwarz::initialize: AdditiveSchwarz doesn't " 01351 "know how to create an instance of your LocalInverseType \"" 01352 << Teuchos::TypeNameTraits<LocalInverseType>::name () << "\". If " 01353 "LocalInverseType is a single-level preconditioner (does not take an " 01354 "inner solver), then you can fix this in one of two ways. Either (a) " 01355 "create the LocalInverseType instance yourself and give it to " 01356 "AdditiveSchwarz by calling setInnerPreconditioner(), before calling " 01357 "initialize(), or (b) teach Details::OneLevelFactory how to create an " 01358 "inner preconditioner of that type. " 01359 "Please talk to the Ifpack2 developers for details."); 01360 01361 TEUCHOS_TEST_FOR_EXCEPTION( 01362 innerName == "CUSTOM", std::runtime_error, "Ifpack2::AdditiveSchwarz::" 01363 "initialize: If the \"inner preconditioner name\" parameter (or any " 01364 "alias thereof) has the value \"CUSTOM\", then you must first call " 01365 "setInnerPreconditioner with a nonnull inner preconditioner input before " 01366 "you may call initialize()."); 01367 01368 Details::OneLevelFactory<MatrixType> factory; 01369 RCP<prec_type> innerPrec = factory.create (innerName, innerMatrix_); 01370 TEUCHOS_TEST_FOR_EXCEPTION( 01371 innerPrec.is_null (), std::logic_error, 01372 "Ifpack2::AdditiveSchwarz::setup: Failed to create inner preconditioner " 01373 "with name \"" << innerName << "\"."); 01374 01375 // Extract and apply the sublist of parameters to give to the 01376 // inner solver, if there is such a sublist of parameters. 01377 std::pair<Teuchos::ParameterList, bool> result = innerPrecParams (); 01378 if (result.second) { 01379 innerPrec->setParameters (result.first); 01380 } 01381 Inverse_ = innerPrec; // "Commit" the inner solver. 01382 } 01383 else if (Inverse_->getMatrix ().getRawPtr () != innerMatrix_.getRawPtr ()) { 01384 // The new inner matrix is different from the inner 01385 // preconditioner's current matrix, so give the inner 01386 // preconditioner the new inner matrix. First make sure that the 01387 // inner solver knows how to have its matrix changed. 01388 typedef Details::CanChangeMatrix<row_matrix_type> can_change_type; 01389 can_change_type* innerSolver = 01390 dynamic_cast<can_change_type*> (Inverse_.getRawPtr ()); 01391 TEUCHOS_TEST_FOR_EXCEPTION( 01392 innerSolver == NULL, std::invalid_argument, "Ifpack2::AdditiveSchwarz::" 01393 "setup: The current inner preconditioner does not implement the " 01394 "setMatrix() feature. Only preconditioners that inherit from " 01395 "Ifpack2::Details::CanChangeMatrix implement this feature."); 01396 01397 // Give the new inner matrix to the inner preconditioner. 01398 innerSolver->setMatrix (innerMatrix_); 01399 } 01400 TEUCHOS_TEST_FOR_EXCEPTION( 01401 Inverse_.is_null (), std::logic_error, "Ifpack2::AdditiveSchwarz::" 01402 "setup: Inverse_ is null right after we were supposed to have created it." 01403 " Please report this bug to the Ifpack2 developers."); 01404 01405 // We don't have to call setInnerPreconditioner() here, because we 01406 // had the inner matrix (innerMatrix_) before creation of the inner 01407 // preconditioner. Calling setInnerPreconditioner here would be 01408 // legal, but it would require an unnecessary reset of the inner 01409 // preconditioner (i.e., calling initialize() and compute() again). 01410 } 01411 01412 01413 template<class MatrixType, class LocalInverseType> 01414 void AdditiveSchwarz<MatrixType, LocalInverseType>:: 01415 setInnerPreconditioner (const Teuchos::RCP<Preconditioner<scalar_type, 01416 local_ordinal_type, 01417 global_ordinal_type, 01418 node_type> >& innerPrec) 01419 { 01420 if (! innerPrec.is_null ()) { 01421 // Make sure that the new inner solver knows how to have its matrix changed. 01422 typedef Details::CanChangeMatrix<row_matrix_type> can_change_type; 01423 can_change_type* innerSolver = dynamic_cast<can_change_type*> (&*innerPrec); 01424 TEUCHOS_TEST_FOR_EXCEPTION( 01425 innerSolver == NULL, std::invalid_argument, "Ifpack2::AdditiveSchwarz::" 01426 "setInnerPreconditioner: The input preconditioner does not implement the " 01427 "setMatrix() feature. Only input preconditioners that inherit from " 01428 "Ifpack2::Details::CanChangeMatrix implement this feature."); 01429 01430 // If users provide an inner solver, we assume that 01431 // AdditiveSchwarz's current inner solver parameters no longer 01432 // apply. (In fact, we will remove those parameters from 01433 // AdditiveSchwarz's current list below.) Thus, we do /not/ apply 01434 // the current sublist of inner solver parameters to the input 01435 // inner solver. 01436 01437 // mfh 03 Jan 2014: Thanks to Paul Tsuji for pointing out that it's 01438 // perfectly legal for innerMatrix_ to be null here. This can 01439 // happen if initialize() has not been called yet. For example, 01440 // when Factory creates an AdditiveSchwarz instance, it calls 01441 // setInnerPreconditioner() without first calling initialize(). 01442 01443 // Give the local matrix to the new inner solver. 01444 innerSolver->setMatrix (innerMatrix_); 01445 01446 // If the user previously specified a parameter for the inner 01447 // preconditioner's type, then clear out that parameter and its 01448 // associated sublist. Replace the inner preconditioner's type with 01449 // "CUSTOM", to make it obvious that AdditiveSchwarz's ParameterList 01450 // does not necessarily describe the current inner preconditioner. 01451 // We have to remove all allowed aliases of "inner preconditioner 01452 // name" before we may set it to "CUSTOM". Users may also set this 01453 // parameter to "CUSTOM" themselves, but this is not required. 01454 removeInnerPrecName (); 01455 removeInnerPrecParams (); 01456 List_.set ("inner preconditioner name", "CUSTOM"); 01457 01458 // Bring the new inner solver's current status (initialized or 01459 // computed) in line with AdditiveSchwarz's current status. 01460 if (isInitialized ()) { 01461 innerPrec->initialize (); 01462 } 01463 if (isComputed ()) { 01464 innerPrec->compute (); 01465 } 01466 } 01467 01468 // If the new inner solver is null, we don't change the initialized 01469 // or computed status of AdditiveSchwarz. That way, AdditiveSchwarz 01470 // won't have to recompute innerMatrix_ if the inner solver changes. 01471 // This does introduce a new error condition in compute() and 01472 // apply(), but that's OK. 01473 01474 // Set the new inner solver. 01475 Inverse_ = innerPrec; 01476 } 01477 01478 template<class MatrixType, class LocalInverseType> 01479 void AdditiveSchwarz<MatrixType, LocalInverseType>:: 01480 setMatrix (const Teuchos::RCP<const row_matrix_type>& A) 01481 { 01482 // Don't set the matrix unless it is different from the current one. 01483 if (A.getRawPtr () != Matrix_.getRawPtr ()) { 01484 IsInitialized_ = false; 01485 IsComputed_ = false; 01486 01487 // Reset all the state computed in initialize() and compute(). 01488 Condest_ = -Teuchos::ScalarTraits<magnitude_type>::one (); 01489 OverlappingMatrix_ = Teuchos::null; 01490 ReorderedLocalizedMatrix_ = Teuchos::null; 01491 innerMatrix_ = Teuchos::null; 01492 SingletonMatrix_ = Teuchos::null; 01493 localMap_ = Teuchos::null; 01494 DistributedImporter_ = Teuchos::null; 01495 01496 Matrix_ = A; 01497 } 01498 } 01499 01500 } // namespace Ifpack2 01501 01502 // FIXME (mfh 16 Sep 2014) We should really only use RowMatrix here! 01503 // There's no need to instantiate for CrsMatrix too. All Ifpack2 01504 // preconditioners can and should do dynamic casts if they need a type 01505 // more specific than RowMatrix. 01506 #define IFPACK2_ADDITIVESCHWARZ_INSTANT(S,LO,GO,N) \ 01507 template class Ifpack2::AdditiveSchwarz< Tpetra::RowMatrix<S, LO, GO, N> >; \ 01508 template class Ifpack2::AdditiveSchwarz< Tpetra::CrsMatrix<S, LO, GO, N> >; \ 01509 template class Ifpack2::AdditiveSchwarz< Tpetra::RowMatrix<S, LO, GO, N>, \ 01510 Ifpack2::ILUT<Tpetra::RowMatrix< S, LO, GO, N > > >; \ 01511 template class Ifpack2::AdditiveSchwarz< Tpetra::CrsMatrix<S, LO, GO, N>, \ 01512 Ifpack2::ILUT<Tpetra::CrsMatrix< S, LO, GO, N > > >; 01513 01514 01515 #endif // IFPACK2_ADDITIVESCHWARZ_DECL_HPP
1.7.6.1