Ifpack2 Templated Preconditioning Package  Version 1.0
Ifpack2_AdditiveSchwarz_def.hpp
Go to the documentation of this file.
1 /*@HEADER
2 // ***********************************************************************
3 //
4 // Ifpack2: Tempated Object-Oriented Algebraic Preconditioner Package
5 // Copyright (2009) Sandia Corporation
6 //
7 // Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive
8 // license for use of this work by or on behalf of the U.S. Government.
9 //
10 // Redistribution and use in source and binary forms, with or without
11 // modification, are permitted provided that the following conditions are
12 // met:
13 //
14 // 1. Redistributions of source code must retain the above copyright
15 // notice, this list of conditions and the following disclaimer.
16 //
17 // 2. Redistributions in binary form must reproduce the above copyright
18 // notice, this list of conditions and the following disclaimer in the
19 // documentation and/or other materials provided with the distribution.
20 //
21 // 3. Neither the name of the Corporation nor the names of the
22 // contributors may be used to endorse or promote products derived from
23 // this software without specific prior written permission.
24 //
25 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
26 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
29 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
30 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
31 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
32 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
33 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
34 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
35 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 //
37 // Questions? Contact Michael A. Heroux (maherou@sandia.gov)
38 //
39 // ***********************************************************************
40 //@HEADER
41 */
42 
54 
55 #ifndef IFPACK2_ADDITIVESCHWARZ_DEF_HPP
56 #define IFPACK2_ADDITIVESCHWARZ_DEF_HPP
57 
59 // We need Ifpack2's implementation of LinearSolver, because we use it
60 // to wrap the user-provided Ifpack2::Preconditioner in
61 // Ifpack2::AdditiveSchwarz::setInnerPreconditioner.
62 #include "Ifpack2_Details_LinearSolver.hpp"
63 
64 #if defined(HAVE_IFPACK2_XPETRA) && defined(HAVE_IFPACK2_ZOLTAN2)
65 #include "Zoltan2_TpetraRowGraphAdapter.hpp"
66 #include "Zoltan2_OrderingProblem.hpp"
67 #include "Zoltan2_OrderingSolution.hpp"
68 #endif
69 
71 #include "Ifpack2_LocalFilter.hpp"
72 #include "Ifpack2_OverlappingRowMatrix.hpp"
73 #include "Ifpack2_Parameters.hpp"
74 #include "Ifpack2_ReorderFilter.hpp"
75 #include "Ifpack2_SingletonFilter.hpp"
76 
77 #ifdef HAVE_MPI
79 #endif
80 
81 #include "Teuchos_StandardParameterEntryValidators.hpp"
82 #include <locale> // std::toupper
83 
84 
85 // FIXME (mfh 25 Aug 2015) Work-around for Bug 6392. This doesn't
86 // need to be a weak symbol because it only refers to a function in
87 // the Ifpack2 package.
88 namespace Ifpack2 {
89 namespace Details {
90  extern void registerLinearSolverFactory ();
91 } // namespace Details
92 } // namespace Ifpack2
93 
94 
95 namespace Ifpack2 {
96 
97 
98 template<class MatrixType, class LocalInverseType>
99 bool
100 AdditiveSchwarz<MatrixType, LocalInverseType>::hasInnerPrecName () const
101 {
102  const char* options[4] = {
103  "inner preconditioner name",
104  "subdomain solver name",
105  "schwarz: inner preconditioner name",
106  "schwarz: subdomain solver name"
107  };
108  const int numOptions = 4;
109  bool match = false;
110  for (int k = 0; k < numOptions && ! match; ++k) {
111  if (List_.isParameter (options[k])) {
112  return true;
113  }
114  }
115  return false;
116 }
117 
118 
119 template<class MatrixType, class LocalInverseType>
120 void
121 AdditiveSchwarz<MatrixType, LocalInverseType>::removeInnerPrecName ()
122 {
123  const char* options[4] = {
124  "inner preconditioner name",
125  "subdomain solver name",
126  "schwarz: inner preconditioner name",
127  "schwarz: subdomain solver name"
128  };
129  const int numOptions = 4;
130  for (int k = 0; k < numOptions; ++k) {
131  List_.remove (options[k], false);
132  }
133 }
134 
135 
136 template<class MatrixType, class LocalInverseType>
137 std::string
138 AdditiveSchwarz<MatrixType, LocalInverseType>::innerPrecName () const
139 {
140  const char* options[4] = {
141  "inner preconditioner name",
142  "subdomain solver name",
143  "schwarz: inner preconditioner name",
144  "schwarz: subdomain solver name"
145  };
146  const int numOptions = 4;
147  std::string newName;
148  bool match = false;
149 
150  // As soon as one parameter option matches, ignore all others.
151  for (int k = 0; k < numOptions && ! match; ++k) {
152  if (List_.isParameter (options[k])) {
153  // try-catch block protects against incorrect type errors.
154  //
155  // FIXME (mfh 04 Jan 2013) We should instead catch and report
156  // type errors.
157  try {
158  newName = List_.get<std::string> (options[k]);
159  match = true;
160  } catch (...) {}
161  }
162  }
163  return match ? newName : defaultInnerPrecName ();
164 }
165 
166 
167 template<class MatrixType, class LocalInverseType>
168 void
169 AdditiveSchwarz<MatrixType, LocalInverseType>::removeInnerPrecParams ()
170 {
171  const char* options[4] = {
172  "inner preconditioner parameters",
173  "subdomain solver parameters",
174  "schwarz: inner preconditioner parameters",
175  "schwarz: subdomain solver parameters"
176  };
177  const int numOptions = 4;
178 
179  // As soon as one parameter option matches, ignore all others.
180  for (int k = 0; k < numOptions; ++k) {
181  List_.remove (options[k], false);
182  }
183 }
184 
185 
186 template<class MatrixType, class LocalInverseType>
187 std::pair<Teuchos::ParameterList, bool>
188 AdditiveSchwarz<MatrixType, LocalInverseType>::innerPrecParams () const
189 {
190  const char* options[4] = {
191  "inner preconditioner parameters",
192  "subdomain solver parameters",
193  "schwarz: inner preconditioner parameters",
194  "schwarz: subdomain solver parameters"
195  };
196  const int numOptions = 4;
197  Teuchos::ParameterList params;
198 
199  // As soon as one parameter option matches, ignore all others.
200  bool match = false;
201  for (int k = 0; k < numOptions && ! match; ++k) {
202  if (List_.isSublist (options[k])) {
203  params = List_.sublist (options[k]);
204  match = true;
205  }
206  }
207  // Default is an empty list of parameters.
208  return std::make_pair (params, match);
209 }
210 
211 
212 template<class MatrixType, class LocalInverseType>
213 std::string
214 AdditiveSchwarz<MatrixType, LocalInverseType>::defaultInnerPrecName ()
215 {
216  // The default inner preconditioner is "ILUT", for backwards
217  // compatibility with the original AdditiveSchwarz implementation.
218  return "ILUT";
219 }
220 
221 
222 template<class MatrixType, class LocalInverseType>
225  Matrix_ (A),
226  IsInitialized_ (false),
227  IsComputed_ (false),
228  IsOverlapping_ (false),
229  OverlapLevel_ (0),
230  CombineMode_ (Tpetra::ZERO),
231  UseReordering_ (false),
232  ReorderingAlgorithm_ ("none"),
233  FilterSingletons_ (false),
234  NumIterations_(1),
235  ZeroStartingSolution_(true),
236  NumInitialize_ (0),
237  NumCompute_ (0),
238  NumApply_ (0),
239  InitializeTime_ (0.0),
240  ComputeTime_ (0.0),
241  ApplyTime_ (0.0)
242 {
244  setParameters (plist); // Set parameters to default values
245 }
246 
247 template<class MatrixType, class LocalInverseType>
250  const int overlapLevel) :
251  Matrix_ (A),
252  IsInitialized_ (false),
253  IsComputed_ (false),
254  IsOverlapping_ (false),
255  OverlapLevel_ (overlapLevel),
256  CombineMode_ (Tpetra::ZERO),
257  UseReordering_ (false),
258  ReorderingAlgorithm_ ("none"),
259  FilterSingletons_ (false),
260  NumIterations_(1),
261  ZeroStartingSolution_(true),
262  NumInitialize_ (0),
263  NumCompute_ (0),
264  NumApply_ (0),
265  InitializeTime_ (0.0),
266  ComputeTime_ (0.0),
267  ApplyTime_ (0.0)
268 {
270  setParameters (plist); // Set parameters to default values
271 }
272 
273 
274 template<class MatrixType,class LocalInverseType>
276 
277 
278 template<class MatrixType,class LocalInverseType>
281 {
283  Matrix_.is_null (), std::runtime_error, "Ifpack2::AdditiveSchwarz::"
284  "getDomainMap: The matrix to precondition is null. You must either pass "
285  "a nonnull matrix to the constructor, or call setMatrix() with a nonnull "
286  "input, before you may call this method.");
287  return Matrix_->getDomainMap ();
288 }
289 
290 
291 template<class MatrixType,class LocalInverseType>
294 {
296  Matrix_.is_null (), std::runtime_error, "Ifpack2::AdditiveSchwarz::"
297  "getRangeMap: The matrix to precondition is null. You must either pass "
298  "a nonnull matrix to the constructor, or call setMatrix() with a nonnull "
299  "input, before you may call this method.");
300  return Matrix_->getRangeMap ();
301 }
302 
303 
304 template<class MatrixType,class LocalInverseType>
306 {
307  return Matrix_;
308 }
309 
310 
311 template<class MatrixType,class LocalInverseType>
312 void
314 apply (const Tpetra::MultiVector<scalar_type,local_ordinal_type,global_ordinal_type,node_type> &B,
315  Tpetra::MultiVector<scalar_type,local_ordinal_type,global_ordinal_type,node_type> &Y,
316  Teuchos::ETransp mode,
317  scalar_type alpha,
318  scalar_type beta) const
319 {
320  using Teuchos::Time;
321  using Teuchos::TimeMonitor;
322  using Teuchos::RCP;
323  using Teuchos::rcp;
324  using Teuchos::rcp_dynamic_cast;
326  const char prefix[] = "Ifpack2::AdditiveSchwarz::apply: ";
327 
329  (! IsComputed_, std::runtime_error,
330  prefix << "isComputed() must be true before you may call apply().");
332  (Matrix_.is_null (), std::logic_error, prefix <<
333  "The input matrix A is null, but the preconditioner says that it has "
334  "been computed (isComputed() is true). This should never happen, since "
335  "setMatrix() should always mark the preconditioner as not computed if "
336  "its argument is null. "
337  "Please report this bug to the Ifpack2 developers.");
339  (Inverse_.is_null (), std::runtime_error,
340  prefix << "The subdomain solver is null. "
341  "This can only happen if you called setInnerPreconditioner() with a null "
342  "input, after calling initialize() or compute(). If you choose to call "
343  "setInnerPreconditioner() with a null input, you must then call it with "
344  "a nonnull input before you may call initialize() or compute().");
346  (B.getNumVectors() != Y.getNumVectors(), std::invalid_argument,
347  prefix << "B and Y must have the same number of columns. B has " <<
348  B.getNumVectors () << " columns, but Y has " << Y.getNumVectors() << ".");
350  (IsOverlapping_ && OverlappingMatrix_.is_null (), std::logic_error,
351  prefix << "The overlapping matrix is null. "
352  "This should never happen if IsOverlapping_ is true. "
353  "Please report this bug to the Ifpack2 developers.");
355  (! IsOverlapping_ && localMap_.is_null (), std::logic_error,
356  prefix << "localMap_ is null. "
357  "This should never happen if IsOverlapping_ is false. "
358  "Please report this bug to the Ifpack2 developers.");
360  (alpha != STS::one (), std::logic_error,
361  prefix << "Not implemented for alpha != 1.");
363  (beta != STS::zero (), std::logic_error,
364  prefix << "Not implemented for beta != 0.");
365 
366 #ifdef HAVE_IFPACK2_DEBUG
367  {
368  typedef typename STS::magnitudeType magnitude_type;
370  Teuchos::Array<magnitude_type> norms (B.getNumVectors ());
371  B.norm2 (norms ());
372  bool good = true;
373  for (size_t j = 0; j < B.getNumVectors (); ++j) {
374  if (STM::isnaninf (norms[j])) {
375  good = false;
376  break;
377  }
378  }
380  (! good, std::runtime_error, "Ifpack2::AdditiveSchwarz::apply: "
381  "The 2-norm of the input B is NaN or Inf.");
382  }
383 #endif // HAVE_IFPACK2_DEBUG
384 
385 #ifdef HAVE_IFPACK2_DEBUG
386  if (! ZeroStartingSolution_) {
387  typedef typename STS::magnitudeType magnitude_type;
389  Teuchos::Array<magnitude_type> norms (Y.getNumVectors ());
390  Y.norm2 (norms ());
391  bool good = true;
392  for (size_t j = 0; j < Y.getNumVectors (); ++j) {
393  if (STM::isnaninf (norms[j])) {
394  good = false;
395  break;
396  }
397  }
399  (! good, std::runtime_error, "Ifpack2::AdditiveSchwarz::apply: "
400  "On input, the initial guess Y has 2-norm NaN or Inf "
401  "(ZeroStartingSolution_ is false).");
402  }
403 #endif // HAVE_IFPACK2_DEBUG
404 
405  const std::string timerName ("Ifpack2::AdditiveSchwarz::apply");
406  RCP<Time> timer = TimeMonitor::lookupCounter (timerName);
407  if (timer.is_null ()) {
408  timer = TimeMonitor::getNewCounter (timerName);
409  }
410 
411  { // Start timing here.
412  TimeMonitor timeMon (*timer);
413 
415  //const scalar_type ONE = Teuchos::ScalarTraits<scalar_type>::one (); // unused
416  const size_t numVectors = B.getNumVectors ();
417 
418  // mfh 25 Apr 2015: Fix for currently failing
419  // Ifpack2_AdditiveSchwarz_RILUK test.
420  if (ZeroStartingSolution_) {
421  Y.putScalar (ZERO);
422  }
423 
424  // set up for overlap communication
425  RCP<MV> OverlappingB,OverlappingY;
426  RCP<MV> globalOverlappingB;
427  if (IsOverlapping_) {
428  // MV's constructor fills with zeros.
429  OverlappingB = rcp (new MV (OverlappingMatrix_->getRowMap (), numVectors));
430  OverlappingY = rcp (new MV (OverlappingMatrix_->getRowMap (), numVectors));
431  }
432  else {
433  // MV's constructor fills with zeros.
434  //
435  // localMap_ has the same number of indices on each process that
436  // Matrix_->getRowMap() does on that process. Thus, we can do
437  // the Import step without creating a new MV, just by viewing
438  // OverlappingB using Matrix_->getRowMap ().
439  OverlappingB = rcp (new MV (localMap_, numVectors));
440  OverlappingY = rcp (new MV (localMap_, numVectors));
441 
442  globalOverlappingB =
443  OverlappingB->offsetViewNonConst (Matrix_->getRowMap (), 0);
444 
445  // Create Import object on demand, if necessary.
446  if (DistributedImporter_.is_null ()) {
447  // FIXME (mfh 15 Apr 2014) Why can't we just ask the Matrix
448  // for its Import object? Of course a general RowMatrix might
449  // not necessarily have one.
450  DistributedImporter_ =
451  rcp (new import_type (Matrix_->getRowMap (),
452  Matrix_->getDomainMap ()));
453  }
454  }
455 
456  RCP<MV> R = rcp(new MV(B.getMap(),numVectors));
457  RCP<MV> C = rcp(new MV(Y.getMap(),numVectors)); //TODO no need to initialize to zero?
458 
459  for (int ni=0; ni<NumIterations_; ++ni)
460  {
461 #ifdef HAVE_IFPACK2_DEBUG
462  {
463  typedef typename STS::magnitudeType magnitude_type;
465  Teuchos::Array<magnitude_type> norms (Y.getNumVectors ());
466  Y.norm2 (norms ());
467  bool good = true;
468  for (size_t j = 0;
469  j < Y.getNumVectors (); ++j) {
470  if (STM::isnaninf (norms[j])) {
471  good = false;
472  break;
473  }
474  }
476  (! good, std::runtime_error, "Ifpack2::AdditiveSchwarz::apply: "
477  "At top of iteration " << ni << ", the 2-norm of Y is NaN or Inf.");
478  }
479 #endif // HAVE_IFPACK2_DEBUG
480 
481  Tpetra::deep_copy(*R, B);
482 
483  // if (ZeroStartingSolution_ && ni == 0) {
484  // Y.putScalar (STS::zero ());
485  // }
486  if (!ZeroStartingSolution_ || ni > 0) {
487  //calculate residual
488  Matrix_->apply (Y, *R, mode, -STS::one(), STS::one());
489 
490 #ifdef HAVE_IFPACK2_DEBUG
491  {
492  typedef typename STS::magnitudeType magnitude_type;
494  Teuchos::Array<magnitude_type> norms (R->getNumVectors ());
495  R->norm2 (norms ());
496  bool good = true;
497  for (size_t j = 0; j < R->getNumVectors (); ++j) {
498  if (STM::isnaninf (norms[j])) {
499  good = false;
500  break;
501  }
502  }
504  (! good, std::runtime_error, "Ifpack2::AdditiveSchwarz::apply: "
505  "At iteration " << ni << ", the 2-norm of R (result of computing "
506  "residual with Y) is NaN or Inf.");
507  }
508 #endif // HAVE_IFPACK2_DEBUG
509  }
510 
511  typedef OverlappingRowMatrix<row_matrix_type> overlap_mat_type;
512  RCP<overlap_mat_type> overlapMatrix;
513  if (IsOverlapping_) {
514  overlapMatrix = rcp_dynamic_cast<overlap_mat_type> (OverlappingMatrix_);
516  (overlapMatrix.is_null (), std::logic_error, prefix <<
517  "IsOverlapping_ is true, but OverlappingMatrix_, while nonnull, is "
518  "not an OverlappingRowMatrix<row_matrix_type>. Please report this "
519  "bug to the Ifpack2 developers.");
520  }
521 
522  // do communication if necessary
523  if (IsOverlapping_) {
525  (overlapMatrix.is_null (), std::logic_error, prefix
526  << "overlapMatrix is null when it shouldn't be. "
527  "Please report this bug to the Ifpack2 developers.");
528  overlapMatrix->importMultiVector (*R, *OverlappingB, Tpetra::INSERT);
529 
530  //JJH We don't need to import the solution Y we are always solving AY=R with initial guess zero
531  //if (ZeroStartingSolution_ == false)
532  // overlapMatrix->importMultiVector (Y, *OverlappingY, Tpetra::INSERT);
533  /*
534  FIXME from Ifpack1: Will not work with non-zero starting solutions.
535  TODO JJH 3/20/15 I don't know whether this comment is still valid.
536 
537  Here is the log for the associated commit 720b2fa4 to Ifpack1:
538 
539  "Added a note to recall that the nonzero starting solution will not
540  work properly if reordering, filtering or wider overlaps are used. This only
541  applied to methods like Jacobi, Gauss-Seidel, and SGS (in both point and block
542  version), and not to ILU-type preconditioners."
543  */
544 
545 #ifdef HAVE_IFPACK2_DEBUG
546  {
547  typedef typename STS::magnitudeType magnitude_type;
549  Teuchos::Array<magnitude_type> norms (OverlappingB->getNumVectors ());
550  OverlappingB->norm2 (norms ());
551  bool good = true;
552  for (size_t j = 0;
553  j < OverlappingB->getNumVectors (); ++j) {
554  if (STM::isnaninf (norms[j])) {
555  good = false;
556  break;
557  }
558  }
560  (! good, std::runtime_error, "Ifpack2::AdditiveSchwarz::apply: "
561  "At iteration " << ni << ", result of importMultiVector from R "
562  "to OverlappingB, has 2-norm NaN or Inf.");
563  }
564 #endif // HAVE_IFPACK2_DEBUG
565  } else {
566  globalOverlappingB->doImport (*R, *DistributedImporter_, Tpetra::INSERT);
567 
568 #ifdef HAVE_IFPACK2_DEBUG
569  {
570  typedef typename STS::magnitudeType magnitude_type;
572  Teuchos::Array<magnitude_type> norms (globalOverlappingB->getNumVectors ());
573  globalOverlappingB->norm2 (norms ());
574  bool good = true;
575  for (size_t j = 0;
576  j < globalOverlappingB->getNumVectors (); ++j) {
577  if (STM::isnaninf (norms[j])) {
578  good = false;
579  break;
580  }
581  }
583  (! good, std::runtime_error, "Ifpack2::AdditiveSchwarz::apply: "
584  "At iteration " << ni << ", result of doImport from R, has 2-norm "
585  "NaN or Inf.");
586  }
587 #endif // HAVE_IFPACK2_DEBUG
588  }
589 
590 #ifdef HAVE_IFPACK2_DEBUG
591  {
592  typedef typename STS::magnitudeType magnitude_type;
594  Teuchos::Array<magnitude_type> norms (OverlappingB->getNumVectors ());
595  OverlappingB->norm2 (norms ());
596  bool good = true;
597  for (size_t j = 0;
598  j < OverlappingB->getNumVectors (); ++j) {
599  if (STM::isnaninf (norms[j])) {
600  good = false;
601  break;
602  }
603  }
605  (! good, std::runtime_error, "Ifpack2::AdditiveSchwarz::apply: "
606  "At iteration " << ni << ", right before localApply, the 2-norm of "
607  "OverlappingB is NaN or Inf.");
608  }
609 #endif // HAVE_IFPACK2_DEBUG
610 
611  // local solve
612  localApply(*OverlappingB, *OverlappingY);
613 
614 #ifdef HAVE_IFPACK2_DEBUG
615  {
616  typedef typename STS::magnitudeType magnitude_type;
618  Teuchos::Array<magnitude_type> norms (OverlappingY->getNumVectors ());
619  OverlappingY->norm2 (norms ());
620  bool good = true;
621  for (size_t j = 0;
622  j < OverlappingY->getNumVectors (); ++j) {
623  if (STM::isnaninf (norms[j])) {
624  good = false;
625  break;
626  }
627  }
629  (! good, std::runtime_error, "Ifpack2::AdditiveSchwarz::apply: "
630  "At iteration " << ni << ", after localApply and before export / "
631  "copy, the 2-norm of OverlappingY is NaN or Inf.");
632  }
633 #endif // HAVE_IFPACK2_DEBUG
634 
635 #ifdef HAVE_IFPACK2_DEBUG
636  {
637  typedef typename STS::magnitudeType magnitude_type;
639  Teuchos::Array<magnitude_type> norms (C->getNumVectors ());
640  C->norm2 (norms ());
641  bool good = true;
642  for (size_t j = 0;
643  j < C->getNumVectors (); ++j) {
644  if (STM::isnaninf (norms[j])) {
645  good = false;
646  break;
647  }
648  }
650  (! good, std::runtime_error, "Ifpack2::AdditiveSchwarz::apply: "
651  "At iteration " << ni << ", before export / copy, the 2-norm of C "
652  "is NaN or Inf.");
653  }
654 #endif // HAVE_IFPACK2_DEBUG
655 
656  // do communication if necessary
657  if (IsOverlapping_) {
659  (overlapMatrix.is_null (), std::logic_error, prefix
660  << "overlapMatrix is null when it shouldn't be. "
661  "Please report this bug to the Ifpack2 developers.");
662  overlapMatrix->exportMultiVector (*OverlappingY, *C, CombineMode_);
663  }
664  else {
665  // mfh 16 Apr 2014: Make a view of Y with the same Map as
666  // OverlappingY, so that we can copy OverlappingY into Y. This
667  // replaces code that iterates over all entries of OverlappingY,
668  // copying them one at a time into Y. That code assumed that
669  // the rows of Y and the rows of OverlappingY have the same
670  // global indices in the same order; see Bug 5992.
671  RCP<MV> C_view = C->offsetViewNonConst (OverlappingY->getMap (), 0);
672  Tpetra::deep_copy (*C_view, *OverlappingY);
673  }
674 
675 #ifdef HAVE_IFPACK2_DEBUG
676  {
677  typedef typename STS::magnitudeType magnitude_type;
679  Teuchos::Array<magnitude_type> norms (C->getNumVectors ());
680  C->norm2 (norms ());
681  bool good = true;
682  for (size_t j = 0;
683  j < C->getNumVectors (); ++j) {
684  if (STM::isnaninf (norms[j])) {
685  good = false;
686  break;
687  }
688  }
690  (! good, std::runtime_error, "Ifpack2::AdditiveSchwarz::apply: "
691  "At iteration " << ni << ", before Y := C + Y, the 2-norm of C "
692  "is NaN or Inf.");
693  }
694 #endif // HAVE_IFPACK2_DEBUG
695 
696 #ifdef HAVE_IFPACK2_DEBUG
697  {
698  typedef typename STS::magnitudeType magnitude_type;
700  Teuchos::Array<magnitude_type> norms (Y.getNumVectors ());
701  Y.norm2 (norms ());
702  bool good = true;
703  for (size_t j = 0;
704  j < Y.getNumVectors (); ++j) {
705  if (STM::isnaninf (norms[j])) {
706  good = false;
707  break;
708  }
709  }
711  (! good, std::runtime_error, "Ifpack2::AdditiveSchwarz::apply: "
712  "Before Y := C + Y, at iteration " << ni << ", the 2-norm of Y "
713  "is NaN or Inf.");
714  }
715 #endif // HAVE_IFPACK2_DEBUG
716 
717  Y.update(STS::one(), *C, STS::one());
718 
719 #ifdef HAVE_IFPACK2_DEBUG
720  {
721  typedef typename STS::magnitudeType magnitude_type;
723  Teuchos::Array<magnitude_type> norms (Y.getNumVectors ());
724  Y.norm2 (norms ());
725  bool good = true;
726  for (size_t j = 0; j < Y.getNumVectors (); ++j) {
727  if (STM::isnaninf (norms[j])) {
728  good = false;
729  break;
730  }
731  }
733  ( ! good, std::runtime_error, "Ifpack2::AdditiveSchwarz::apply: "
734  "At iteration " << ni << ", after Y := C + Y, the 2-norm of Y "
735  "is NaN or Inf.");
736  }
737 #endif // HAVE_IFPACK2_DEBUG
738  }
739 
740  } // Stop timing here.
741 
742 #ifdef HAVE_IFPACK2_DEBUG
743  {
744  typedef typename STS::magnitudeType magnitude_type;
746  Teuchos::Array<magnitude_type> norms (Y.getNumVectors ());
747  Y.norm2 (norms ());
748  bool good = true;
749  for (size_t j = 0; j < Y.getNumVectors (); ++j) {
750  if (STM::isnaninf (norms[j])) {
751  good = false;
752  break;
753  }
754  }
756  ( ! good, std::runtime_error, "Ifpack2::AdditiveSchwarz::apply: "
757  "The 2-norm of the output Y is NaN or Inf.");
758  }
759 #endif // HAVE_IFPACK2_DEBUG
760 
761  ++NumApply_;
762 
763  // timer->totalElapsedTime() returns the total time over all timer
764  // calls. Thus, we use = instead of +=.
765  ApplyTime_ = timer->totalElapsedTime ();
766 }
767 
768 template<class MatrixType,class LocalInverseType>
769 void
771 localApply(MV &OverlappingB, MV &OverlappingY) const
772 {
773  using Teuchos::RCP;
774  using Teuchos::rcp_dynamic_cast;
775 
776  const size_t numVectors = OverlappingB.getNumVectors ();
777  if (FilterSingletons_) {
778  // process singleton filter
779  MV ReducedB (SingletonMatrix_->getRowMap (), numVectors);
780  MV ReducedY (SingletonMatrix_->getRowMap (), numVectors);
781 
782  RCP<SingletonFilter<row_matrix_type> > singletonFilter =
783  rcp_dynamic_cast<SingletonFilter<row_matrix_type> > (SingletonMatrix_);
785  (! SingletonMatrix_.is_null () && singletonFilter.is_null (),
786  std::logic_error, "Ifpack2::AdditiveSchwarz::localApply: "
787  "SingletonFilter_ is nonnull but is not a SingletonFilter"
788  "<row_matrix_type>. This should never happen. Please report this bug "
789  "to the Ifpack2 developers.");
790  singletonFilter->SolveSingletons (OverlappingB, OverlappingY);
791  singletonFilter->CreateReducedRHS (OverlappingY, OverlappingB, ReducedB);
792 
793  // process reordering
794  if (! UseReordering_) {
795  Inverse_->solve (ReducedY, ReducedB);
796  }
797  else {
798  RCP<ReorderFilter<row_matrix_type> > rf =
799  rcp_dynamic_cast<ReorderFilter<row_matrix_type> > (ReorderedLocalizedMatrix_);
801  (! ReorderedLocalizedMatrix_.is_null () && rf.is_null (), std::logic_error,
802  "Ifpack2::AdditiveSchwarz::localApply: ReorderedLocalizedMatrix_ is "
803  "nonnull but is not a ReorderFilter<row_matrix_type>. This should "
804  "never happen. Please report this bug to the Ifpack2 developers.");
805  MV ReorderedB (ReducedB, Teuchos::Copy);
806  MV ReorderedY (ReducedY, Teuchos::Copy);
807  rf->permuteOriginalToReordered (ReducedB, ReorderedB);
808  Inverse_->solve (ReorderedY, ReorderedB);
809  rf->permuteReorderedToOriginal (ReorderedY, ReducedY);
810  }
811 
812  // finish up with singletons
813  singletonFilter->UpdateLHS (ReducedY, OverlappingY);
814  }
815  else {
816 
817  // process reordering
818  if (! UseReordering_) {
819  Inverse_->solve (OverlappingY, OverlappingB);
820  }
821  else {
822  MV ReorderedB (OverlappingB, Teuchos::Copy);
823  MV ReorderedY (OverlappingY, Teuchos::Copy);
824 
825  RCP<ReorderFilter<row_matrix_type> > rf =
826  rcp_dynamic_cast<ReorderFilter<row_matrix_type> > (ReorderedLocalizedMatrix_);
828  (! ReorderedLocalizedMatrix_.is_null () && rf.is_null (), std::logic_error,
829  "Ifpack2::AdditiveSchwarz::localApply: ReorderedLocalizedMatrix_ is "
830  "nonnull but is not a ReorderFilter<row_matrix_type>. This should "
831  "never happen. Please report this bug to the Ifpack2 developers.");
832  rf->permuteOriginalToReordered (OverlappingB, ReorderedB);
833  Inverse_->solve (ReorderedY, ReorderedB);
834  rf->permuteReorderedToOriginal (ReorderedY, OverlappingY);
835  }
836  }
837 }
838 
839 
840 template<class MatrixType,class LocalInverseType>
843 {
844  // mfh 18 Nov 2013: Ifpack2's setParameters() method passes in the
845  // input list as const. This means that we have to copy it before
846  // validation or passing into setParameterList().
847  List_ = plist;
848  this->setParameterList (Teuchos::rcpFromRef (List_));
849 }
850 
851 
852 
853 template<class MatrixType,class LocalInverseType>
856 {
857  using Tpetra::CombineMode;
858  using Teuchos::getIntegralValue;
862  using Teuchos::RCP;
863  using Teuchos::rcp;
864  using Teuchos::rcp_dynamic_cast;
866 
867  if (plist.is_null ()) {
868  // Assume that the user meant to set default parameters by passing
869  // in an empty list.
870  this->setParameterList (rcp (new ParameterList ()));
871  }
872  // FIXME (mfh 26 Aug 2015) It's not necessarily true that plist is
873  // nonnull at this point.
874 
875  // At this point, plist should be nonnull.
877  plist.is_null (), std::logic_error, "Ifpack2::AdditiveSchwarz::"
878  "setParameterList: plist is null. This should never happen, since the "
879  "method should have replaced a null input list with a nonnull empty list "
880  "by this point. Please report this bug to the Ifpack2 developers.");
881 
882  // TODO JJH 24March2015 The list needs to be validated. Not sure why this is commented out.
883  // try {
884  // List_.validateParameters (* getValidParameters ());
885  // }
886  // catch (std::exception& e) {
887  // std::cerr << "Ifpack2::AdditiveSchwarz::setParameterList: Validation failed with the following error message: " << e.what () << std::endl;
888  // throw e;
889  // }
890 
891  // mfh 18 Nov 2013: Supplying the current value as the default value
892  // when calling ParameterList::get() ensures "delta" behavior when
893  // users pass in new parameters: any unspecified parameters in the
894  // new list retain their values in the old list. This preserves
895  // backwards compatiblity with this class' previous behavior. Note
896  // that validateParametersAndSetDefaults() would have different
897  // behavior: any parameters not in the new list would get default
898  // values, which could be different than their values in the
899  // original list.
900 
901  bool gotCombineMode = false;
902  try {
903  CombineMode_ = getIntegralValue<Tpetra::CombineMode> (List_, "schwarz: combine mode");
904  gotCombineMode = true;
905  }
907  // The caller didn't provide that parameter. Just keep the
908  // existing value of CombineMode_.
909  gotCombineMode = true;
910  }
912  // The user perhaps supplied it as an Tpetra::CombineMode enum
913  // value. Let's try again (below). If it doesn't succeed, we
914  // know that the type is wrong, so we can let it throw whatever
915  // exception it would throw.
916  }
917  // Try to get the combine mode as an integer.
918  if (! gotCombineMode) {
919  try {
920  CombineMode_ = plist->get ("schwarz: combine mode", CombineMode_);
921  gotCombineMode = true;
922  }
924  }
925  // Try to get the combine mode as a string. If this works, use the
926  // validator to convert to int. This is painful, but necessary in
927  // order to do validation, since the input list doesn't come with a
928  // validator.
929  if (! gotCombineMode) {
930  const ParameterEntry& validEntry =
931  getValidParameters ()->getEntry ("schwarz: combine mode");
932  RCP<const ParameterEntryValidator> v = validEntry.validator ();
933  typedef StringToIntegralParameterEntryValidator<CombineMode> vs2e_type;
934  RCP<const vs2e_type> vs2e = rcp_dynamic_cast<const vs2e_type> (v, true);
935 
936  const ParameterEntry& inputEntry = plist->getEntry ("schwarz: combine mode");
937  CombineMode_ = vs2e->getIntegralValue (inputEntry, "schwarz: combine mode");
938  gotCombineMode = true;
939  }
940  (void) gotCombineMode; // forestall "set but not used" compiler warning
941 
942  OverlapLevel_ = plist->get ("schwarz: overlap level", OverlapLevel_);
943 
944  // We set IsOverlapping_ in initialize(), once we know that Matrix_ is nonnull.
945 
946  // Will we be doing reordering? Unlike Ifpack, we'll use a
947  // "schwarz: reordering list" to give to Zoltan2.
948  UseReordering_ = plist->get ("schwarz: use reordering", UseReordering_);
949 
950 #if !defined(HAVE_IFPACK2_XPETRA) || !defined(HAVE_IFPACK2_ZOLTAN2)
952  UseReordering_, std::invalid_argument, "Ifpack2::AdditiveSchwarz::"
953  "setParameters: You specified \"schwarz: use reordering\" = true. "
954  "This is only valid when Trilinos was built with Ifpack2, Xpetra, and "
955  "Zoltan2 enabled. Either Xpetra or Zoltan2 was not enabled in your build "
956  "of Trilinos.");
957 #endif
958 
959  // FIXME (mfh 18 Nov 2013) Now would be a good time to validate the
960  // "schwarz: reordering list" parameter list. Currently, that list
961  // gets extracted in setup().
962 
963  // if true, filter singletons. NOTE: the filtered matrix can still have
964  // singletons! A simple example: upper triangular matrix, if I remove
965  // the lower node, I still get a matrix with a singleton! However, filter
966  // singletons should help for PDE problems with Dirichlet BCs.
967  FilterSingletons_ = plist->get ("schwarz: filter singletons", FilterSingletons_);
968 
969  // If the inner solver doesn't exist yet, don't create it.
970  // initialize() creates it.
971  //
972  // If the inner solver _does_ exist, there are three cases,
973  // depending on what the user put in the input ParameterList.
974  //
975  // 1. The user did /not/ provide a parameter specifying the inner
976  // solver's type, nor did the user specify a sublist of
977  // parameters for the inner solver
978  // 2. The user did /not/ provide a parameter specifying the inner
979  // solver's type, but /did/ specify a sublist of parameters for
980  // the inner solver
981  // 3. The user provided a parameter specifying the inner solver's
982  // type (it does not matter in this case whether the user gave
983  // a sublist of parameters for the inner solver)
984  //
985  // AdditiveSchwarz has "delta" (relative) semantics for setting
986  // parameters. This means that if the user did not specify the
987  // inner solver's type, we presume that the type has not changed.
988  // Thus, if the inner solver exists, we don't need to recreate it.
989  //
990  // In Case 3, if the user bothered to specify the inner solver's
991  // type, then we must assume it may differ than the current inner
992  // solver's type. Thus, we have to recreate the inner solver. We
993  // achieve this here by assigning null to Inverse_; initialize()
994  // will recreate the solver when it is needed. Our assumption here
995  // is necessary because Ifpack2::Preconditioner does not have a
996  // method for querying a preconditioner's "type" (i.e., name) as a
997  // string. Remember that the user may have previously set an
998  // arbitrary inner solver by calling setInnerPreconditioner().
999  //
1000  // See note at the end of setInnerPreconditioner().
1001 
1002  if (! Inverse_.is_null ()) {
1003  // "CUSTOM" explicitly indicates that the user called or plans to
1004  // call setInnerPreconditioner.
1005  if (hasInnerPrecName () && innerPrecName () != "CUSTOM") {
1006  // Wipe out the current inner solver. initialize() will
1007  // recreate it with the correct type.
1008  Inverse_ = Teuchos::null;
1009  }
1010  else {
1011  // Extract and apply the sublist of parameters to give to the
1012  // inner solver, if there is such a sublist of parameters.
1013  std::pair<Teuchos::ParameterList, bool> result = innerPrecParams ();
1014  if (result.second) {
1015  // FIXME (mfh 26 Aug 2015) Rewrite innerPrecParams() so this
1016  // isn't another deep copy.
1017  Inverse_->setParameters (rcp (new ParameterList (result.first)));
1018  }
1019  }
1020  }
1021 
1022  NumIterations_ = plist->get<int>("schwarz: num iterations", NumIterations_);
1023  ZeroStartingSolution_ = plist->get<bool>("schwarz: zero starting solution", ZeroStartingSolution_);
1024 }
1025 
1026 
1027 
1028 template<class MatrixType,class LocalInverseType>
1032 {
1033  using Teuchos::ParameterList;
1034  using Teuchos::parameterList;
1035  using Teuchos::RCP;
1036  using Teuchos::rcp_const_cast;
1037 
1038  if (validParams_.is_null ()) {
1039  const int overlapLevel = 0;
1040  const bool useReordering = false;
1041  const bool filterSingletons = false;
1042  const int numIterations = 1;
1043  const bool zeroStartingSolution = true;
1044  ParameterList reorderingSublist;
1045  reorderingSublist.set ("order_method", std::string ("rcm"));
1046 
1047  RCP<ParameterList> plist = parameterList ("Ifpack2::AdditiveSchwarz");
1048 
1049  Tpetra::setCombineModeParameter (*plist, "schwarz: combine mode");
1050  plist->set ("schwarz: overlap level", overlapLevel);
1051  plist->set ("schwarz: use reordering", useReordering);
1052  plist->set ("schwarz: reordering list", reorderingSublist);
1053  // mfh 24 Mar 2015: We accept this for backwards compatibility
1054  // ONLY. It is IGNORED.
1055  plist->set ("schwarz: compute condest", false);
1056  plist->set ("schwarz: filter singletons", filterSingletons);
1057  plist->set ("schwarz: num iterations", numIterations);
1058  plist->set ("schwarz: zero starting solution", zeroStartingSolution);
1059 
1060  // FIXME (mfh 18 Nov 2013) Get valid parameters from inner solver.
1061  // JJH The inner solver should handle its own validation.
1062  //
1063  // FIXME (mfh 18 Nov 2013) Get valid parameters from Zoltan2, if
1064  // Zoltan2 was enabled in the build.
1065  // JJH Zoltan2 should handle its own validation.
1066  //
1067 
1068  validParams_ = rcp_const_cast<const ParameterList> (plist);
1069  }
1070  return validParams_;
1071 }
1072 
1073 
1074 template<class MatrixType,class LocalInverseType>
1076 {
1077  using Tpetra::global_size_t;
1078  using Teuchos::RCP;
1079  using Teuchos::rcp;
1080  using Teuchos::SerialComm;
1081  using Teuchos::Time;
1082  using Teuchos::TimeMonitor;
1083 
1084  const std::string timerName ("Ifpack2::AdditiveSchwarz::initialize");
1085  RCP<Time> timer = TimeMonitor::lookupCounter (timerName);
1086  if (timer.is_null ()) {
1087  timer = TimeMonitor::getNewCounter (timerName);
1088  }
1089 
1090  { // Start timing here.
1091  TimeMonitor timeMon (*timer);
1092 
1094  Matrix_.is_null (), std::runtime_error, "Ifpack2::AdditiveSchwarz::"
1095  "initialize: The matrix to precondition is null. You must either pass "
1096  "a nonnull matrix to the constructor, or call setMatrix() with a nonnull "
1097  "input, before you may call this method.");
1098 
1099  IsInitialized_ = false;
1100  IsComputed_ = false;
1101 
1102  RCP<const Teuchos::Comm<int> > comm = Matrix_->getComm ();
1103  RCP<const map_type> rowMap = Matrix_->getRowMap ();
1104  RCP<node_type> node = Matrix_->getNode ();
1105  const global_size_t INVALID =
1107 
1108  // If there's only one process in the matrix's communicator,
1109  // then there's no need to compute overlap.
1110  if (comm->getSize () == 1) {
1111  OverlapLevel_ = 0;
1112  IsOverlapping_ = false;
1113  } else if (OverlapLevel_ != 0) {
1114  IsOverlapping_ = true;
1115  }
1116 
1117  if (OverlapLevel_ == 0) {
1118  const global_ordinal_type indexBase = rowMap->getIndexBase ();
1119  RCP<const SerialComm<int> > localComm (new SerialComm<int> ());
1120  // FIXME (mfh 15 Apr 2014) What if indexBase isn't the least
1121  // global index in the list of GIDs on this process?
1122  localMap_ =
1123  rcp (new map_type (INVALID, rowMap->getNodeNumElements (),
1124  indexBase, localComm, node));
1125  }
1126 
1127  // compute the overlapping matrix if necessary
1128  if (IsOverlapping_) {
1129  OverlappingMatrix_ = rcp (new OverlappingRowMatrix<row_matrix_type> (Matrix_, OverlapLevel_));
1130  }
1131 
1132  setup (); // This does a lot of the initialization work.
1133 
1134  if (! Inverse_.is_null ()) {
1135  Inverse_->symbolic (); // Initialize subdomain solver.
1136  }
1137 
1138  } // Stop timing here.
1139 
1140  IsInitialized_ = true;
1141  ++NumInitialize_;
1142 
1143  // timer->totalElapsedTime() returns the total time over all timer
1144  // calls. Thus, we use = instead of +=.
1145  InitializeTime_ = timer->totalElapsedTime ();
1146 }
1147 
1148 
1149 template<class MatrixType,class LocalInverseType>
1151 {
1152  return IsInitialized_;
1153 }
1154 
1155 
1156 template<class MatrixType,class LocalInverseType>
1158 {
1159  using Teuchos::RCP;
1160  using Teuchos::Time;
1161  using Teuchos::TimeMonitor;
1162 
1163  if (! IsInitialized_) {
1164  initialize ();
1165  }
1166 
1168  ! isInitialized (), std::logic_error, "Ifpack2::AdditiveSchwarz::compute: "
1169  "The preconditioner is not yet initialized, "
1170  "even though initialize() supposedly has been called. "
1171  "This should never happen. "
1172  "Please report this bug to the Ifpack2 developers.");
1173 
1175  Inverse_.is_null (), std::runtime_error,
1176  "Ifpack2::AdditiveSchwarz::compute: The subdomain solver is null. "
1177  "This can only happen if you called setInnerPreconditioner() with a null "
1178  "input, after calling initialize() or compute(). If you choose to call "
1179  "setInnerPreconditioner() with a null input, you must then call it with a "
1180  "nonnull input before you may call initialize() or compute().");
1181 
1182  const std::string timerName ("Ifpack2::AdditiveSchwarz::compute");
1183  RCP<Time> timer = TimeMonitor::lookupCounter (timerName);
1184  if (timer.is_null ()) {
1185  timer = TimeMonitor::getNewCounter (timerName);
1186  }
1187 
1188  { // Start timing here.
1189  TimeMonitor timeMon (*timer);
1190 
1191  IsComputed_ = false;
1192  Inverse_->numeric ();
1193  } // Stop timing here.
1194 
1195  IsComputed_ = true;
1196  ++NumCompute_;
1197 
1198  // timer->totalElapsedTime() returns the total time over all timer
1199  // calls. Thus, we use = instead of +=.
1200  ComputeTime_ = timer->totalElapsedTime ();
1201 }
1202 
1203 //==============================================================================
1204 // Returns true if the preconditioner has been successfully computed, false otherwise.
1205 template<class MatrixType,class LocalInverseType>
1207 {
1208  return IsComputed_;
1209 }
1210 
1211 
1212 template<class MatrixType,class LocalInverseType>
1214 {
1215  return NumInitialize_;
1216 }
1217 
1218 
1219 template<class MatrixType,class LocalInverseType>
1221 {
1222  return NumCompute_;
1223 }
1224 
1225 
1226 template<class MatrixType,class LocalInverseType>
1228 {
1229  return NumApply_;
1230 }
1231 
1232 
1233 template<class MatrixType,class LocalInverseType>
1235 {
1236  return InitializeTime_;
1237 }
1238 
1239 
1240 template<class MatrixType,class LocalInverseType>
1242 {
1243  return ComputeTime_;
1244 }
1245 
1246 
1247 template<class MatrixType,class LocalInverseType>
1249 {
1250  return ApplyTime_;
1251 }
1252 
1253 
1254 template<class MatrixType,class LocalInverseType>
1256 {
1257  std::ostringstream out;
1258 
1259  out << "\"Ifpack2::AdditiveSchwarz\": {";
1260  if (this->getObjectLabel () != "") {
1261  out << "Label: \"" << this->getObjectLabel () << "\", ";
1262  }
1263  out << "Initialized: " << (isInitialized () ? "true" : "false")
1264  << ", Computed: " << (isComputed () ? "true" : "false")
1265  << ", Iterations: " << NumIterations_
1266  << ", Overlap level: " << OverlapLevel_
1267  << ", Subdomain reordering: \"" << ReorderingAlgorithm_ << "\"";
1268  out << ", Combine mode: \"";
1269  if (CombineMode_ == Tpetra::INSERT) {
1270  out << "INSERT";
1271  } else if (CombineMode_ == Tpetra::ADD) {
1272  out << "ADD";
1273  } else if (CombineMode_ == Tpetra::REPLACE) {
1274  out << "REPLACE";
1275  } else if (CombineMode_ == Tpetra::ABSMAX) {
1276  out << "ABSMAX";
1277  } else if (CombineMode_ == Tpetra::ZERO) {
1278  out << "ZERO";
1279  }
1280  out << "\"";
1281  if (Matrix_.is_null ()) {
1282  out << ", Matrix: null";
1283  }
1284  else {
1285  out << ", Global matrix dimensions: ["
1286  << Matrix_->getGlobalNumRows () << ", "
1287  << Matrix_->getGlobalNumCols () << "]";
1288  }
1289  out << ", Inner solver: ";
1290  if (! Inverse_.is_null ()) {
1292  Teuchos::rcp_dynamic_cast<Teuchos::Describable> (Inverse_);
1293  if (! inv.is_null ()) {
1294  out << "{" << inv->description () << "}";
1295  } else {
1296  out << "{" << "Some inner solver" << "}";
1297  }
1298  } else {
1299  out << "null";
1300  }
1301 
1302  out << "}";
1303  return out.str ();
1304 }
1305 
1306 
1307 template<class MatrixType,class LocalInverseType>
1308 void
1311  const Teuchos::EVerbosityLevel verbLevel) const
1312 {
1313  using Teuchos::OSTab;
1315  using std::endl;
1316 
1317  const int myRank = Matrix_->getComm ()->getRank ();
1318  const int numProcs = Matrix_->getComm ()->getSize ();
1319  const Teuchos::EVerbosityLevel vl =
1320  (verbLevel == Teuchos::VERB_DEFAULT) ? Teuchos::VERB_LOW : verbLevel;
1321 
1322  if (vl > Teuchos::VERB_NONE) {
1323  // describe() starts with a tab, by convention.
1324  OSTab tab0 (out);
1325  if (myRank == 0) {
1326  out << "\"Ifpack2::AdditiveSchwarz\":";
1327  }
1328  OSTab tab1 (out);
1329  if (myRank == 0) {
1330  out << "MatrixType: " << TypeNameTraits<MatrixType>::name () << endl;
1331  out << "LocalInverseType: " << TypeNameTraits<LocalInverseType>::name () << endl;
1332  if (this->getObjectLabel () != "") {
1333  out << "Label: \"" << this->getObjectLabel () << "\"" << endl;
1334  }
1335 
1336  out << "Overlap level: " << OverlapLevel_ << endl
1337  << "Combine mode: \"";
1338  if (CombineMode_ == Tpetra::INSERT) {
1339  out << "INSERT";
1340  } else if (CombineMode_ == Tpetra::ADD) {
1341  out << "ADD";
1342  } else if (CombineMode_ == Tpetra::REPLACE) {
1343  out << "REPLACE";
1344  } else if (CombineMode_ == Tpetra::ABSMAX) {
1345  out << "ABSMAX";
1346  } else if (CombineMode_ == Tpetra::ZERO) {
1347  out << "ZERO";
1348  }
1349  out << "\"" << endl
1350  << "Subdomain reordering: \"" << ReorderingAlgorithm_ << "\"" << endl;
1351  }
1352 
1353  if (Matrix_.is_null ()) {
1354  if (myRank == 0) {
1355  out << "Matrix: null" << endl;
1356  }
1357  }
1358  else {
1359  if (myRank == 0) {
1360  out << "Matrix:" << endl;
1361  std::flush (out);
1362  }
1363  Matrix_->getComm ()->barrier (); // wait for output to finish
1364  Matrix_->describe (out, Teuchos::VERB_LOW);
1365  }
1366 
1367  if (myRank == 0) {
1368  out << "Number of initialize calls: " << getNumInitialize () << endl
1369  << "Number of compute calls: " << getNumCompute () << endl
1370  << "Number of apply calls: " << getNumApply () << endl
1371  << "Total time in seconds for initialize: " << getInitializeTime () << endl
1372  << "Total time in seconds for compute: " << getComputeTime () << endl
1373  << "Total time in seconds for apply: " << getApplyTime () << endl;
1374  }
1375 
1376  if (Inverse_.is_null ()) {
1377  if (myRank == 0) {
1378  out << "Subdomain solver: null" << endl;
1379  }
1380  }
1381  else {
1382  if (vl < Teuchos::VERB_EXTREME) {
1383  if (myRank == 0) {
1384  out << "Subdomain solver: not null" << endl;
1385  }
1386  }
1387  else { // vl >= Teuchos::VERB_EXTREME
1388  for (int p = 0; p < numProcs; ++p) {
1389  if (p == myRank) {
1390  out << "Subdomain solver on Process " << myRank << ":";
1391  if (Inverse_.is_null ()) {
1392  out << "null" << endl;
1393  } else {
1395  Teuchos::rcp_dynamic_cast<Teuchos::Describable> (Inverse_);
1396  if (! inv.is_null ()) {
1397  out << endl;
1398  inv->describe (out, vl);
1399  } else {
1400  out << "null" << endl;
1401  }
1402  }
1403  }
1404  Matrix_->getComm ()->barrier ();
1405  Matrix_->getComm ()->barrier ();
1406  Matrix_->getComm ()->barrier (); // wait for output to finish
1407  }
1408  }
1409  }
1410 
1411  Matrix_->getComm ()->barrier (); // wait for output to finish
1412  }
1413 }
1414 
1415 
1416 template<class MatrixType,class LocalInverseType>
1417 std::ostream& AdditiveSchwarz<MatrixType,LocalInverseType>::print(std::ostream& os) const
1418 {
1419  Teuchos::FancyOStream fos(Teuchos::rcp(&os,false));
1420  fos.setOutputToRootOnly(0);
1421  describe(fos);
1422  return(os);
1423 }
1424 
1425 
1426 template<class MatrixType,class LocalInverseType>
1428 {
1429  return OverlapLevel_;
1430 }
1431 
1432 
1433 template<class MatrixType,class LocalInverseType>
1435 {
1436 #ifdef HAVE_MPI
1437  using Teuchos::MpiComm;
1438 #endif // HAVE_MPI
1439  using Teuchos::ArrayRCP;
1440  using Teuchos::ParameterList;
1441  using Teuchos::RCP;
1442  using Teuchos::rcp;
1443  using Teuchos::rcp_dynamic_cast;
1444  using Teuchos::rcpFromRef;
1445 
1447  Matrix_.is_null (), std::runtime_error, "Ifpack2::AdditiveSchwarz::"
1448  "initialize: The matrix to precondition is null. You must either pass "
1449  "a nonnull matrix to the constructor, or call setMatrix() with a nonnull "
1450  "input, before you may call this method.");
1451 
1452  // Localized version of Matrix_ or OverlappingMatrix_.
1453  RCP<row_matrix_type> LocalizedMatrix;
1454 
1455  // The "most current local matrix." At the end of this method, this
1456  // will be handed off to the inner solver.
1457  RCP<row_matrix_type> ActiveMatrix;
1458 
1459  // Create localized matrix.
1460  if (! OverlappingMatrix_.is_null ()) {
1461  LocalizedMatrix = rcp (new LocalFilter<row_matrix_type> (OverlappingMatrix_));
1462  }
1463  else {
1464  LocalizedMatrix = rcp (new LocalFilter<row_matrix_type> (Matrix_));
1465  }
1466 
1467  // Sanity check; I don't trust the logic above to have created LocalizedMatrix.
1469  LocalizedMatrix.is_null (), std::logic_error,
1470  "Ifpack2::AdditiveSchwarz::setup: LocalizedMatrix is null, after the code "
1471  "that claimed to have created it. This should never be the case. Please "
1472  "report this bug to the Ifpack2 developers.");
1473 
1474  // Mark localized matrix as active
1475  ActiveMatrix = LocalizedMatrix;
1476 
1477  // Singleton Filtering
1478  if (FilterSingletons_) {
1479  SingletonMatrix_ = rcp (new SingletonFilter<row_matrix_type> (LocalizedMatrix));
1480  ActiveMatrix = SingletonMatrix_;
1481  }
1482 
1483  // Do reordering
1484  if (UseReordering_) {
1485 #if defined(HAVE_IFPACK2_XPETRA) && defined(HAVE_IFPACK2_ZOLTAN2)
1486  // Unlike Ifpack, Zoltan2 does all the dirty work here.
1487  Teuchos::ParameterList zlist = List_.sublist ("schwarz: reordering list");
1488 
1489  // FIXME (mfh 18 Nov 2013) Shouldn't this come from the Zoltan2 sublist?
1490  ReorderingAlgorithm_ = List_.get<std::string> ("order_method", "rcm");
1491 
1492  typedef Tpetra::RowGraph
1493  <local_ordinal_type, global_ordinal_type, node_type> row_graph_type;
1494  typedef Zoltan2::TpetraRowGraphAdapter<row_graph_type> z2_adapter_type;
1495  RCP<const row_graph_type> constActiveGraph =
1496  Teuchos::rcp_const_cast<const row_graph_type>(ActiveMatrix->getGraph());
1497  z2_adapter_type Zoltan2Graph (constActiveGraph);
1498 
1499  typedef Zoltan2::OrderingProblem<z2_adapter_type> ordering_problem_type;
1500 #ifdef HAVE_MPI
1501  // Grab the MPI Communicator and build the ordering problem with that
1502  MPI_Comm myRawComm;
1503 
1504  RCP<const MpiComm<int> > mpicomm =
1505  rcp_dynamic_cast<const MpiComm<int> > (ActiveMatrix->getComm ());
1506  if (mpicomm == Teuchos::null) {
1507  myRawComm = MPI_COMM_SELF;
1508  } else {
1509  myRawComm = * (mpicomm->getRawMpiComm ());
1510  }
1511  ordering_problem_type MyOrderingProblem (&Zoltan2Graph, &zlist, myRawComm);
1512 #else
1513  ordering_problem_type MyOrderingProblem (&Zoltan2Graph, &zlist);
1514 #endif
1515  MyOrderingProblem.solve ();
1516 
1517  // Now create the reordered matrix & mark it as active
1518  {
1519  typedef ReorderFilter<row_matrix_type> reorder_filter_type;
1520  typedef Zoltan2::OrderingSolution<local_ordinal_type,
1521  global_ordinal_type> ordering_solution_type;
1522 
1523  ordering_solution_type sol (*MyOrderingProblem.getSolution ());
1524 
1525  // perm[i] gives the where OLD index i shows up in the NEW
1526  // ordering. revperm[i] gives the where NEW index i shows
1527  // up in the OLD ordering. Note that perm is actually the
1528  // "inverse permutation," in Zoltan2 terms.
1529  ArrayRCP<local_ordinal_type> perm = sol.getPermutationRCPConst (true);
1530  ArrayRCP<local_ordinal_type> revperm = sol.getPermutationRCPConst ();
1531 
1532  ReorderedLocalizedMatrix_ =
1533  rcp (new reorder_filter_type (ActiveMatrix, perm, revperm));
1534 
1535  ActiveMatrix = ReorderedLocalizedMatrix_;
1536  }
1537 #else
1538  // This is a logic_error, not a runtime_error, because
1539  // setParameters() should have excluded this case already.
1541  true, std::logic_error, "Ifpack2::AdditiveSchwarz::setup: "
1542  "The Zoltan2 and Xpetra packages must be enabled in order "
1543  "to support reordering.");
1544 #endif
1545  }
1546 
1547  innerMatrix_ = ActiveMatrix;
1548 
1550  innerMatrix_.is_null (), std::logic_error, "Ifpack2::AdditiveSchwarz::"
1551  "setup: Inner matrix is null right before constructing inner solver. "
1552  "Please report this bug to the Ifpack2 developers.");
1553 
1554  // Construct the inner solver if necessary.
1555  if (Inverse_.is_null ()) {
1556  const std::string innerName = innerPrecName ();
1558  innerName == "INVALID", std::logic_error,
1559  "Ifpack2::AdditiveSchwarz::initialize: AdditiveSchwarz doesn't "
1560  "know how to create an instance of your LocalInverseType \""
1562  "Please talk to the Ifpack2 developers for details.");
1563 
1565  innerName == "CUSTOM", std::runtime_error, "Ifpack2::AdditiveSchwarz::"
1566  "initialize: If the \"inner preconditioner name\" parameter (or any "
1567  "alias thereof) has the value \"CUSTOM\", then you must first call "
1568  "setInnerPreconditioner with a nonnull inner preconditioner input before "
1569  "you may call initialize().");
1570 
1571  // FIXME (mfh 26 Aug 2015) Once we fix Bug 6392, the following
1572  // three lines of code can and SHOULD go away.
1575  }
1576 
1577  // FIXME (mfh 26 Aug 2015) Provide the capability to get inner
1578  // solvers from packages other than Ifpack2.
1579  typedef typename MV::mag_type MT;
1580  RCP<inner_solver_type> innerPrec =
1581  Trilinos::Details::getLinearSolver<MV, OP, MT> ("Ifpack2", innerName);
1583  innerPrec.is_null (), std::logic_error,
1584  "Ifpack2::AdditiveSchwarz::setup: Failed to create inner preconditioner "
1585  "with name \"" << innerName << "\".");
1586  innerPrec->setMatrix (innerMatrix_);
1587 
1588  // Extract and apply the sublist of parameters to give to the
1589  // inner solver, if there is such a sublist of parameters.
1590  std::pair<Teuchos::ParameterList, bool> result = innerPrecParams ();
1591  if (result.second) {
1592  // FIXME (mfh 26 Aug 2015) We don't really want to use yet
1593  // another deep copy of the ParameterList here.
1594  innerPrec->setParameters (rcp (new ParameterList (result.first)));
1595  }
1596  Inverse_ = innerPrec; // "Commit" the inner solver.
1597  }
1598  else if (Inverse_->getMatrix ().getRawPtr () != innerMatrix_.getRawPtr ()) {
1599  // The new inner matrix is different from the inner
1600  // preconditioner's current matrix, so give the inner
1601  // preconditioner the new inner matrix.
1602  Inverse_->setMatrix (innerMatrix_);
1603  }
1605  Inverse_.is_null (), std::logic_error, "Ifpack2::AdditiveSchwarz::"
1606  "setup: Inverse_ is null right after we were supposed to have created it."
1607  " Please report this bug to the Ifpack2 developers.");
1608 
1609  // We don't have to call setInnerPreconditioner() here, because we
1610  // had the inner matrix (innerMatrix_) before creation of the inner
1611  // preconditioner. Calling setInnerPreconditioner here would be
1612  // legal, but it would require an unnecessary reset of the inner
1613  // preconditioner (i.e., calling initialize() and compute() again).
1614 }
1615 
1616 
1617 template<class MatrixType, class LocalInverseType>
1622  node_type> >& innerPrec)
1623 {
1624  if (! innerPrec.is_null ()) {
1625  // Make sure that the new inner solver knows how to have its matrix changed.
1626  typedef Details::CanChangeMatrix<row_matrix_type> can_change_type;
1627  can_change_type* innerSolver = dynamic_cast<can_change_type*> (&*innerPrec);
1629  innerSolver == NULL, std::invalid_argument, "Ifpack2::AdditiveSchwarz::"
1630  "setInnerPreconditioner: The input preconditioner does not implement the "
1631  "setMatrix() feature. Only input preconditioners that inherit from "
1632  "Ifpack2::Details::CanChangeMatrix implement this feature.");
1633 
1634  // If users provide an inner solver, we assume that
1635  // AdditiveSchwarz's current inner solver parameters no longer
1636  // apply. (In fact, we will remove those parameters from
1637  // AdditiveSchwarz's current list below.) Thus, we do /not/ apply
1638  // the current sublist of inner solver parameters to the input
1639  // inner solver.
1640 
1641  // mfh 03 Jan 2014: Thanks to Paul Tsuji for pointing out that
1642  // it's perfectly legal for innerMatrix_ to be null here. This
1643  // can happen if initialize() has not been called yet. For
1644  // example, when Ifpack2::Factory creates an AdditiveSchwarz
1645  // instance, it calls setInnerPreconditioner() without first
1646  // calling initialize().
1647 
1648  // Give the local matrix to the new inner solver.
1649  innerSolver->setMatrix (innerMatrix_);
1650 
1651  // If the user previously specified a parameter for the inner
1652  // preconditioner's type, then clear out that parameter and its
1653  // associated sublist. Replace the inner preconditioner's type with
1654  // "CUSTOM", to make it obvious that AdditiveSchwarz's ParameterList
1655  // does not necessarily describe the current inner preconditioner.
1656  // We have to remove all allowed aliases of "inner preconditioner
1657  // name" before we may set it to "CUSTOM". Users may also set this
1658  // parameter to "CUSTOM" themselves, but this is not required.
1659  removeInnerPrecName ();
1660  removeInnerPrecParams ();
1661  List_.set ("inner preconditioner name", "CUSTOM");
1662 
1663  // Bring the new inner solver's current status (initialized or
1664  // computed) in line with AdditiveSchwarz's current status.
1665  if (isInitialized ()) {
1666  innerPrec->initialize ();
1667  }
1668  if (isComputed ()) {
1669  innerPrec->compute ();
1670  }
1671  }
1672 
1673  // If the new inner solver is null, we don't change the initialized
1674  // or computed status of AdditiveSchwarz. That way, AdditiveSchwarz
1675  // won't have to recompute innerMatrix_ if the inner solver changes.
1676  // This does introduce a new error condition in compute() and
1677  // apply(), but that's OK.
1678 
1679  // Set the new inner solver.
1681  global_ordinal_type, node_type> inner_solver_impl_type;
1682  Inverse_ = Teuchos::rcp (new inner_solver_impl_type (innerPrec, "CUSTOM"));
1683 }
1684 
1685 template<class MatrixType, class LocalInverseType>
1688 {
1689  // Don't set the matrix unless it is different from the current one.
1690  if (A.getRawPtr () != Matrix_.getRawPtr ()) {
1691  IsInitialized_ = false;
1692  IsComputed_ = false;
1693 
1694  // Reset all the state computed in initialize() and compute().
1695  OverlappingMatrix_ = Teuchos::null;
1696  ReorderedLocalizedMatrix_ = Teuchos::null;
1697  innerMatrix_ = Teuchos::null;
1698  SingletonMatrix_ = Teuchos::null;
1699  localMap_ = Teuchos::null;
1700  DistributedImporter_ = Teuchos::null;
1701 
1702  Matrix_ = A;
1703  }
1704 }
1705 
1706 } // namespace Ifpack2
1707 
1708 // NOTE (mfh 26 Aug 2015) There's no need to instantiate for CrsMatrix
1709 // too. All Ifpack2 preconditioners can and should do dynamic casts
1710 // internally, if they need a type more specific than RowMatrix.
1711 #define IFPACK2_ADDITIVESCHWARZ_INSTANT(S,LO,GO,N) \
1712  template class Ifpack2::AdditiveSchwarz< Tpetra::RowMatrix<S, LO, GO, N> >;
1713 
1714 #endif // IFPACK2_ADDITIVESCHWARZ_DECL_HPP
virtual Teuchos::RCP< const Tpetra::Map< local_ordinal_type, global_ordinal_type, node_type > > getDomainMap() const
The domain Map of this operator.
Definition: Ifpack2_AdditiveSchwarz_def.hpp:280
Mix-in interface for preconditioners that can change their matrix after construction.
Definition: Ifpack2_Details_CanChangeMatrix.hpp:93
void setParameterList(const Teuchos::RCP< Teuchos::ParameterList > &plist)
Set the preconditioner&#39;s parameters.
Definition: Ifpack2_AdditiveSchwarz_def.hpp:855
virtual void compute()
Computes all (coefficient) data necessary to apply the preconditioner.
Definition: Ifpack2_AdditiveSchwarz_def.hpp:1157
VERB_DEFAULT
void registerLinearSolverFactory()
Register Ifpack2&#39;s LinearSolverFactory with the central repository, for all enabled combinations of t...
Definition: Ifpack2_Details_registerLinearSolverFactory.cpp:68
basic_OSTab< char > OSTab
virtual double getInitializeTime() const
Returns the time spent in initialize().
Definition: Ifpack2_AdditiveSchwarz_def.hpp:1234
VERB_LOW
VERB_NONE
virtual double getComputeTime() const
Returns the time spent in compute().
Definition: Ifpack2_AdditiveSchwarz_def.hpp:1241
T & get(const std::string &name, T def_value)
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
VERB_EXTREME
MatrixType::node_type node_type
The Node type used by the input MatrixType.
Definition: Ifpack2_AdditiveSchwarz_decl.hpp:321
virtual Teuchos::RCP< const row_matrix_type > getMatrix() const
The input matrix.
Definition: Ifpack2_AdditiveSchwarz_def.hpp:305
virtual double getApplyTime() const
Returns the time spent in apply().
Definition: Ifpack2_AdditiveSchwarz_def.hpp:1248
virtual ~AdditiveSchwarz()
Destructor.
Definition: Ifpack2_AdditiveSchwarz_def.hpp:275
Teuchos::ScalarTraits< scalar_type >::magnitudeType magnitude_type
The type of the magnitude (absolute value) of a matrix entry.
Definition: Ifpack2_AdditiveSchwarz_decl.hpp:324
std::string description() const
Return a simple one-line description of this object.
Definition: Ifpack2_AdditiveSchwarz_def.hpp:1255
virtual std::string description() const
AdditiveSchwarz(const Teuchos::RCP< const row_matrix_type > &A)
Constructor that takes a matrix.
Definition: Ifpack2_AdditiveSchwarz_def.hpp:224
bool is_null() const
virtual void initialize()
Computes all (graph-related) data necessary to initialize the preconditioner.
Definition: Ifpack2_AdditiveSchwarz_def.hpp:1075
Ifpack2 implementation details.
virtual bool isInitialized() const
Returns true if the preconditioner has been successfully initialized, false otherwise.
Definition: Ifpack2_AdditiveSchwarz_def.hpp:1150
MatrixType::global_ordinal_type global_ordinal_type
The type of global indices in the input MatrixType.
Definition: Ifpack2_AdditiveSchwarz_decl.hpp:318
MatrixType::scalar_type scalar_type
The type of the entries of the input MatrixType.
Definition: Ifpack2_AdditiveSchwarz_decl.hpp:312
bool registeredSomeLinearSolverFactory(const std::string &packageName)
virtual int getOverlapLevel() const
Returns the level of overlap.
Definition: Ifpack2_AdditiveSchwarz_def.hpp:1427
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
virtual void setInnerPreconditioner(const Teuchos::RCP< Preconditioner< scalar_type, local_ordinal_type, global_ordinal_type, node_type > > &innerPrec)
Set the inner preconditioner.
Definition: Ifpack2_AdditiveSchwarz_def.hpp:1619
virtual int getNumCompute() const
Returns the number of calls to compute().
Definition: Ifpack2_AdditiveSchwarz_def.hpp:1220
Ifpack2&#39;s implementation of Trilinos::Details::LinearSolver interface.
Definition: Ifpack2_Details_LinearSolver_decl.hpp:105
Interface for all Ifpack2 preconditioners.
Definition: Ifpack2_Preconditioner.hpp:107
virtual Teuchos::RCP< const Tpetra::Map< local_ordinal_type, global_ordinal_type, node_type > > getRangeMap() const
The range Map of this operator.
Definition: Ifpack2_AdditiveSchwarz_def.hpp:293
basic_FancyOStream & setOutputToRootOnly(const int rootRank)
Teuchos::RCP< const Teuchos::ParameterList > getValidParameters() const
Get a list of the preconditioner&#39;s default parameters.
Definition: Ifpack2_AdditiveSchwarz_def.hpp:1031
Declaration of interface for preconditioners that can change their matrix after construction.
void describe(Teuchos::FancyOStream &out, const Teuchos::EVerbosityLevel verbLevel=Teuchos::Describable::verbLevel_default) const
Print the object with some verbosity level to an FancyOStream object.
Definition: Ifpack2_AdditiveSchwarz_def.hpp:1310
virtual std::ostream & print(std::ostream &os) const
Prints basic information on iostream. This function is used by operator<<.
Definition: Ifpack2_AdditiveSchwarz_def.hpp:1417
virtual void setParameters(const Teuchos::ParameterList &plist)
Set the preconditioner&#39;s parameters.
Definition: Ifpack2_AdditiveSchwarz_def.hpp:842
Sparse matrix (Tpetra::RowMatrix subclass) with ghost rows.
Definition: Ifpack2_OverlappingRowMatrix_decl.hpp:59
T * getRawPtr() const
Additive Schwarz domain decomposition for Tpetra sparse matrices.
Definition: Ifpack2_AdditiveSchwarz_decl.hpp:281
virtual bool isComputed() const
Returns true if the preconditioner has been successfully computed, false otherwise.
Definition: Ifpack2_AdditiveSchwarz_def.hpp:1206
ParameterList & sublist(const std::string &name, bool mustAlreadyExist=false, const std::string &docString="")
Access only local rows and columns of a sparse matrix.
Definition: Ifpack2_LocalFilter_decl.hpp:160
virtual void describe(FancyOStream &out, const EVerbosityLevel verbLevel=verbLevel_default) const
Preconditioners and smoothers for Tpetra sparse matrices.
Definition: Ifpack2_AdditiveSchwarz_decl.hpp:72
void registerLinearSolverFactory(const std::string &packageName, const Teuchos::RCP< LinearSolverFactory< MV, OP, NormType > > &factory)
ParameterEntry & getEntry(const std::string &name)
Filter based on matrix entries.
Definition: Ifpack2_SingletonFilter_decl.hpp:64
virtual void setMatrix(const Teuchos::RCP< const row_matrix_type > &A)
Change the matrix to be preconditioned.
Definition: Ifpack2_AdditiveSchwarz_def.hpp:1687
void getValidParameters(Teuchos::ParameterList &params)
Fills a list which contains all the parameters possibly used by Ifpack2.
Definition: Ifpack2_Parameters.cpp:50
MatrixType::local_ordinal_type local_ordinal_type
The type of local indices in the input MatrixType.
Definition: Ifpack2_AdditiveSchwarz_decl.hpp:315
virtual int getNumInitialize() const
Returns the number of calls to initialize().
Definition: Ifpack2_AdditiveSchwarz_def.hpp:1213
virtual int getNumApply() const
Returns the number of calls to apply().
Definition: Ifpack2_AdditiveSchwarz_def.hpp:1227
virtual void apply(const Tpetra::MultiVector< scalar_type, local_ordinal_type, global_ordinal_type, node_type > &X, Tpetra::MultiVector< scalar_type, local_ordinal_type, global_ordinal_type, node_type > &Y, Teuchos::ETransp mode=Teuchos::NO_TRANS, scalar_type alpha=Teuchos::ScalarTraits< scalar_type >::one(), scalar_type beta=Teuchos::ScalarTraits< scalar_type >::zero()) const
Apply the preconditioner to X, putting the result in Y.
Definition: Ifpack2_AdditiveSchwarz_def.hpp:314