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