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