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