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