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