Ifpack2 Templated Preconditioning Package  Version 1.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends
Ifpack2_AdditiveSchwarz_def.hpp
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
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends