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