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//
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
58#include "Trilinos_Details_LinearSolverFactory.hpp"
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
79#include "Teuchos_DefaultMpiComm.hpp"
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.
91namespace Ifpack2 {
92namespace Details {
93 extern void registerLinearSolverFactory ();
94} // namespace Details
95} // namespace Ifpack2
96
97#ifdef HAVE_IFPACK2_DEBUG
98
99namespace { // (anonymous)
100
101 template<class MV>
102 bool
103 anyBad (const MV& X)
104 {
105 using STS = Teuchos::ScalarTraits<typename MV::scalar_type>;
106 using magnitude_type = typename STS::magnitudeType;
107 using STM = Teuchos::ScalarTraits<magnitude_type>;
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
125namespace Ifpack2 {
126
127template<class MatrixType, class LocalInverseType>
128bool
129AdditiveSchwarz<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
148template<class MatrixType, class LocalInverseType>
149void
150AdditiveSchwarz<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
165template<class MatrixType, class LocalInverseType>
166std::string
167AdditiveSchwarz<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
192template<class MatrixType, class LocalInverseType>
193void
194AdditiveSchwarz<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
211template<class MatrixType, class LocalInverseType>
212std::pair<Teuchos::ParameterList, bool>
213AdditiveSchwarz<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
236template<class MatrixType, class LocalInverseType>
237std::string
238AdditiveSchwarz<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
245template<class MatrixType, class LocalInverseType>
247AdditiveSchwarz (const Teuchos::RCP<const row_matrix_type>& A) :
248 Matrix_ (A)
249{}
250
251template<class MatrixType, class LocalInverseType>
253AdditiveSchwarz (const Teuchos::RCP<const row_matrix_type>& A,
254 const int overlapLevel) :
255 Matrix_ (A),
256 OverlapLevel_ (overlapLevel)
257{}
258
259template<class MatrixType,class LocalInverseType>
260Teuchos::RCP<const Tpetra::Map<typename MatrixType::local_ordinal_type, typename MatrixType::global_ordinal_type, typename MatrixType::node_type > >
262getDomainMap () const
263{
264 TEUCHOS_TEST_FOR_EXCEPTION(
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
273template<class MatrixType,class LocalInverseType>
274Teuchos::RCP<const Tpetra::Map<typename MatrixType::local_ordinal_type, typename MatrixType::global_ordinal_type, typename MatrixType::node_type> >
276{
277 TEUCHOS_TEST_FOR_EXCEPTION(
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
286template<class MatrixType,class LocalInverseType>
287Teuchos::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
288{
289 return Matrix_;
290}
291
292
293namespace
294{
295
296template<class MatrixType, class map_type>
297Teuchos::RCP<const map_type>
298pointMapFromMeshMap(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
313template<class MatrixType,class LocalInverseType>
314void
316apply (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;
327 typedef Teuchos::ScalarTraits<scalar_type> STS;
328 const char prefix[] = "Ifpack2::AdditiveSchwarz::apply: ";
329
330 TEUCHOS_TEST_FOR_EXCEPTION
331 (! IsComputed_, std::runtime_error,
332 prefix << "isComputed() must be true before you may call apply().");
333 TEUCHOS_TEST_FOR_EXCEPTION
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.");
340 TEUCHOS_TEST_FOR_EXCEPTION
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().");
347 TEUCHOS_TEST_FOR_EXCEPTION
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() << ".");
351 TEUCHOS_TEST_FOR_EXCEPTION
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.");
356 TEUCHOS_TEST_FOR_EXCEPTION
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.");
361 TEUCHOS_TEST_FOR_EXCEPTION
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
397 const scalar_type ZERO = Teuchos::ScalarTraits<scalar_type>::zero ();
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
659template<class MatrixType,class LocalInverseType>
660void
662localApply (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_);
694 TEUCHOS_TEST_FOR_EXCEPTION
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_);
710 TEUCHOS_TEST_FOR_EXCEPTION
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_);
736 TEUCHOS_TEST_FOR_EXCEPTION
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
750template<class MatrixType,class LocalInverseType>
752setParameters (const Teuchos::ParameterList& plist)
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
763template<class MatrixType,class LocalInverseType>
765setParameterList (const Teuchos::RCP<Teuchos::ParameterList>& plist)
766{
767 using Tpetra::CombineMode;
768 using Teuchos::ParameterEntry;
769 using Teuchos::ParameterEntryValidator;
770 using Teuchos::ParameterList;
771 using Teuchos::RCP;
772 using Teuchos::rcp;
773 using Teuchos::rcp_dynamic_cast;
774 using Teuchos::StringToIntegralParameterEntryValidator;
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.
787 TEUCHOS_TEST_FOR_EXCEPTION(
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)
876 TEUCHOS_TEST_FOR_EXCEPTION(
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
958template<class MatrixType,class LocalInverseType>
959Teuchos::RCP<const Teuchos::ParameterList>
961getValidParameters () const
962{
963 using Teuchos::ParameterList;
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
1006template<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
1026 TEUCHOS_TEST_FOR_EXCEPTION(
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 =
1042 Teuchos::OrdinalTraits<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
1083template<class MatrixType,class LocalInverseType>
1085{
1086 return IsInitialized_;
1087}
1088
1089
1090template<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
1101 TEUCHOS_TEST_FOR_EXCEPTION(
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
1108 TEUCHOS_TEST_FOR_EXCEPTION(
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_) {
1127 Teuchos::TimeMonitor t(*Teuchos::TimeMonitor::getNewTimer("Halo Import"));
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 {
1135 Teuchos::TimeMonitor t(*Teuchos::TimeMonitor::getNewTimer("Fill Local Matrix"));
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.
1157template<class MatrixType,class LocalInverseType>
1159{
1160 return IsComputed_;
1161}
1162
1163
1164template<class MatrixType,class LocalInverseType>
1166{
1167 return NumInitialize_;
1168}
1169
1170
1171template<class MatrixType,class LocalInverseType>
1173{
1174 return NumCompute_;
1175}
1176
1177
1178template<class MatrixType,class LocalInverseType>
1180{
1181 return NumApply_;
1182}
1183
1184
1185template<class MatrixType,class LocalInverseType>
1187{
1188 return InitializeTime_;
1189}
1190
1191
1192template<class MatrixType,class LocalInverseType>
1194{
1195 return ComputeTime_;
1196}
1197
1198
1199template<class MatrixType,class LocalInverseType>
1201{
1202 return ApplyTime_;
1203}
1204
1205
1206template<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 ()) {
1243 Teuchos::RCP<Teuchos::Describable> inv =
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
1259template<class MatrixType,class LocalInverseType>
1260void
1262describe (Teuchos::FancyOStream& out,
1263 const Teuchos::EVerbosityLevel verbLevel) const
1264{
1265 using Teuchos::OSTab;
1266 using Teuchos::TypeNameTraits;
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 out << "Subdomain solver: not null" << endl;
1337 }
1338 }
1339 else { // vl >= Teuchos::VERB_EXTREME
1340 for (int p = 0; p < numProcs; ++p) {
1341 if (p == myRank) {
1342 out << "Subdomain solver on Process " << myRank << ":";
1343 if (Inverse_.is_null ()) {
1344 out << "null" << endl;
1345 } else {
1346 Teuchos::RCP<Teuchos::Describable> inv =
1347 Teuchos::rcp_dynamic_cast<Teuchos::Describable> (Inverse_);
1348 if (! inv.is_null ()) {
1349 out << endl;
1350 inv->describe (out, vl);
1351 } else {
1352 out << "null" << endl;
1353 }
1354 }
1355 }
1356 Matrix_->getComm ()->barrier ();
1357 Matrix_->getComm ()->barrier ();
1358 Matrix_->getComm ()->barrier (); // wait for output to finish
1359 }
1360 }
1361 }
1362
1363 Matrix_->getComm ()->barrier (); // wait for output to finish
1364 }
1365}
1366
1367
1368template<class MatrixType,class LocalInverseType>
1369std::ostream& AdditiveSchwarz<MatrixType,LocalInverseType>::print(std::ostream& os) const
1370{
1371 Teuchos::FancyOStream fos(Teuchos::rcp(&os,false));
1372 fos.setOutputToRootOnly(0);
1373 describe(fos);
1374 return(os);
1375}
1376
1377
1378template<class MatrixType,class LocalInverseType>
1380{
1381 return OverlapLevel_;
1382}
1383
1384
1385template<class MatrixType,class LocalInverseType>
1386void AdditiveSchwarz<MatrixType,LocalInverseType>::setup ()
1387{
1388#ifdef HAVE_MPI
1389 using Teuchos::MpiComm;
1390#endif // HAVE_MPI
1391 using Teuchos::ArrayRCP;
1392 using Teuchos::ParameterList;
1393 using Teuchos::RCP;
1394 using Teuchos::rcp;
1395 using Teuchos::rcp_dynamic_cast;
1396 using Teuchos::rcpFromRef;
1397
1398 TEUCHOS_TEST_FOR_EXCEPTION(
1399 Matrix_.is_null (), std::runtime_error, "Ifpack2::AdditiveSchwarz::"
1400 "initialize: The matrix to precondition is null. You must either pass "
1401 "a nonnull matrix to the constructor, or call setMatrix() with a nonnull "
1402 "input, before you may call this method.");
1403
1404 //If the matrix is a CrsMatrix or OverlappingRowMatrix, use the high-performance
1405 //AdditiveSchwarzFilter. Otherwise, use composition of Reordered/Singleton/LocalFilter.
1406 auto matrixCrs = rcp_dynamic_cast<const crs_matrix_type>(Matrix_);
1407 if(!OverlappingMatrix_.is_null() || !matrixCrs.is_null())
1408 {
1409 ArrayRCP<local_ordinal_type> perm;
1410 ArrayRCP<local_ordinal_type> revperm;
1411 if (UseReordering_) {
1412 Teuchos::TimeMonitor t(*Teuchos::TimeMonitor::getNewTimer("Reordering"));
1413#if defined(HAVE_IFPACK2_XPETRA) && defined(HAVE_IFPACK2_ZOLTAN2)
1414 // Unlike Ifpack, Zoltan2 does all the dirty work here.
1415 Teuchos::ParameterList zlist = List_.sublist ("schwarz: reordering list");
1416 ReorderingAlgorithm_ = zlist.get<std::string> ("order_method", "rcm");
1417
1418 if(ReorderingAlgorithm_ == "user") {
1419 // User-provided reordering
1420 perm = zlist.get<Teuchos::ArrayRCP<local_ordinal_type> >("user ordering");
1421 revperm = zlist.get<Teuchos::ArrayRCP<local_ordinal_type> >("user reverse ordering");
1422 }
1423 else {
1424 // Zoltan2 reordering
1425 typedef Tpetra::RowGraph
1426 <local_ordinal_type, global_ordinal_type, node_type> row_graph_type;
1427 typedef Zoltan2::TpetraRowGraphAdapter<row_graph_type> z2_adapter_type;
1428 auto constActiveGraph = Teuchos::rcp_const_cast<const row_graph_type>(
1429 IsOverlapping_ ? OverlappingMatrix_->getGraph() : Matrix_->getGraph());
1430 z2_adapter_type Zoltan2Graph (constActiveGraph);
1431
1432 typedef Zoltan2::OrderingProblem<z2_adapter_type> ordering_problem_type;
1433#ifdef HAVE_MPI
1434 // Grab the MPI Communicator and build the ordering problem with that
1435 MPI_Comm myRawComm;
1436
1437 RCP<const MpiComm<int> > mpicomm =
1438 rcp_dynamic_cast<const MpiComm<int> > (Matrix_->getComm ());
1439 if (mpicomm == Teuchos::null) {
1440 myRawComm = MPI_COMM_SELF;
1441 } else {
1442 myRawComm = * (mpicomm->getRawMpiComm ());
1443 }
1444 ordering_problem_type MyOrderingProblem (&Zoltan2Graph, &zlist, myRawComm);
1445#else
1446 ordering_problem_type MyOrderingProblem (&Zoltan2Graph, &zlist);
1447#endif
1448 MyOrderingProblem.solve ();
1449
1450 {
1451 typedef Zoltan2::LocalOrderingSolution<local_ordinal_type>
1452 ordering_solution_type;
1453
1454 ordering_solution_type sol (*MyOrderingProblem.getLocalOrderingSolution());
1455
1456 // perm[i] gives the where OLD index i shows up in the NEW
1457 // ordering. revperm[i] gives the where NEW index i shows
1458 // up in the OLD ordering. Note that perm is actually the
1459 // "inverse permutation," in Zoltan2 terms.
1460 perm = sol.getPermutationRCPConst (true);
1461 revperm = sol.getPermutationRCPConst ();
1462 }
1463 }
1464#else
1465 // This is a logic_error, not a runtime_error, because
1466 // setParameters() should have excluded this case already.
1467 TEUCHOS_TEST_FOR_EXCEPTION(
1468 true, std::logic_error, "Ifpack2::AdditiveSchwarz::setup: "
1469 "The Zoltan2 and Xpetra packages must be enabled in order "
1470 "to support reordering.");
1471#endif
1472 }
1473 else
1474 {
1475 local_ordinal_type numLocalRows = OverlappingMatrix_.is_null() ? matrixCrs->getLocalNumRows() : OverlappingMatrix_->getLocalNumRows();
1476 //Use an identity ordering.
1477 //TODO: create a non-permuted code path in AdditiveSchwarzFilter, in the case that neither
1478 //reordering nor singleton filtering are enabled. In this situation it's like LocalFilter.
1479 perm = ArrayRCP<local_ordinal_type>(numLocalRows);
1480 revperm = ArrayRCP<local_ordinal_type>(numLocalRows);
1481 for(local_ordinal_type i = 0; i < numLocalRows; i++)
1482 {
1483 perm[i] = i;
1484 revperm[i] = i;
1485 }
1486 }
1487 //Now, construct the filter
1488 {
1489 Teuchos::TimeMonitor t(*Teuchos::TimeMonitor::getNewTimer("Filter construction"));
1490 RCP<Details::AdditiveSchwarzFilter<MatrixType>> asf;
1491 if(OverlappingMatrix_.is_null())
1492 asf = rcp(new Details::AdditiveSchwarzFilter<MatrixType>(matrixCrs, perm, revperm, FilterSingletons_));
1493 else
1494 asf = rcp(new Details::AdditiveSchwarzFilter<MatrixType>(OverlappingMatrix_, perm, revperm, FilterSingletons_));
1495 innerMatrix_ = asf;
1496 }
1497 }
1498 else
1499 {
1500 // Localized version of Matrix_ or OverlappingMatrix_.
1501 RCP<row_matrix_type> LocalizedMatrix;
1502
1503 // The "most current local matrix." At the end of this method, this
1504 // will be handed off to the inner solver.
1505 RCP<row_matrix_type> ActiveMatrix;
1506
1507 // Create localized matrix.
1508 if (! OverlappingMatrix_.is_null ()) {
1509 LocalizedMatrix = rcp (new LocalFilter<row_matrix_type> (OverlappingMatrix_));
1510 }
1511 else {
1512 LocalizedMatrix = rcp (new LocalFilter<row_matrix_type> (Matrix_));
1513 }
1514
1515 // Sanity check; I don't trust the logic above to have created LocalizedMatrix.
1516 TEUCHOS_TEST_FOR_EXCEPTION(
1517 LocalizedMatrix.is_null (), std::logic_error,
1518 "Ifpack2::AdditiveSchwarz::setup: LocalizedMatrix is null, after the code "
1519 "that claimed to have created it. This should never be the case. Please "
1520 "report this bug to the Ifpack2 developers.");
1521
1522 // Mark localized matrix as active
1523 ActiveMatrix = LocalizedMatrix;
1524
1525 // Singleton Filtering
1526 if (FilterSingletons_) {
1527 SingletonMatrix_ = rcp (new SingletonFilter<row_matrix_type> (LocalizedMatrix));
1528 ActiveMatrix = SingletonMatrix_;
1529 }
1530
1531 // Do reordering
1532 if (UseReordering_) {
1533#if defined(HAVE_IFPACK2_XPETRA) && defined(HAVE_IFPACK2_ZOLTAN2)
1534 // Unlike Ifpack, Zoltan2 does all the dirty work here.
1535 typedef ReorderFilter<row_matrix_type> reorder_filter_type;
1536 Teuchos::ParameterList zlist = List_.sublist ("schwarz: reordering list");
1537 ReorderingAlgorithm_ = zlist.get<std::string> ("order_method", "rcm");
1538
1539 ArrayRCP<local_ordinal_type> perm;
1540 ArrayRCP<local_ordinal_type> revperm;
1541
1542 if(ReorderingAlgorithm_ == "user") {
1543 // User-provided reordering
1544 perm = zlist.get<Teuchos::ArrayRCP<local_ordinal_type> >("user ordering");
1545 revperm = zlist.get<Teuchos::ArrayRCP<local_ordinal_type> >("user reverse ordering");
1546 }
1547 else {
1548 // Zoltan2 reordering
1549 typedef Tpetra::RowGraph
1551 typedef Zoltan2::TpetraRowGraphAdapter<row_graph_type> z2_adapter_type;
1552 RCP<const row_graph_type> constActiveGraph =
1553 Teuchos::rcp_const_cast<const row_graph_type>(ActiveMatrix->getGraph());
1554 z2_adapter_type Zoltan2Graph (constActiveGraph);
1555
1556 typedef Zoltan2::OrderingProblem<z2_adapter_type> ordering_problem_type;
1557#ifdef HAVE_MPI
1558 // Grab the MPI Communicator and build the ordering problem with that
1559 MPI_Comm myRawComm;
1560
1561 RCP<const MpiComm<int> > mpicomm =
1562 rcp_dynamic_cast<const MpiComm<int> > (ActiveMatrix->getComm ());
1563 if (mpicomm == Teuchos::null) {
1564 myRawComm = MPI_COMM_SELF;
1565 } else {
1566 myRawComm = * (mpicomm->getRawMpiComm ());
1567 }
1568 ordering_problem_type MyOrderingProblem (&Zoltan2Graph, &zlist, myRawComm);
1569#else
1570 ordering_problem_type MyOrderingProblem (&Zoltan2Graph, &zlist);
1571#endif
1572 MyOrderingProblem.solve ();
1573
1574 {
1575 typedef Zoltan2::LocalOrderingSolution<local_ordinal_type>
1576 ordering_solution_type;
1577
1578 ordering_solution_type sol (*MyOrderingProblem.getLocalOrderingSolution());
1579
1580 // perm[i] gives the where OLD index i shows up in the NEW
1581 // ordering. revperm[i] gives the where NEW index i shows
1582 // up in the OLD ordering. Note that perm is actually the
1583 // "inverse permutation," in Zoltan2 terms.
1584 perm = sol.getPermutationRCPConst (true);
1585 revperm = sol.getPermutationRCPConst ();
1586 }
1587 }
1588 // All reorderings here...
1589 ReorderedLocalizedMatrix_ = rcp (new reorder_filter_type (ActiveMatrix, perm, revperm));
1590
1591
1592 ActiveMatrix = ReorderedLocalizedMatrix_;
1593#else
1594 // This is a logic_error, not a runtime_error, because
1595 // setParameters() should have excluded this case already.
1596 TEUCHOS_TEST_FOR_EXCEPTION(
1597 true, std::logic_error, "Ifpack2::AdditiveSchwarz::setup: "
1598 "The Zoltan2 and Xpetra packages must be enabled in order "
1599 "to support reordering.");
1600#endif
1601 }
1602 innerMatrix_ = ActiveMatrix;
1603 }
1604
1605 TEUCHOS_TEST_FOR_EXCEPTION(
1606 innerMatrix_.is_null (), std::logic_error, "Ifpack2::AdditiveSchwarz::"
1607 "setup: Inner matrix is null right before constructing inner solver. "
1608 "Please report this bug to the Ifpack2 developers.");
1609
1610 // Construct the inner solver if necessary.
1611 if (Inverse_.is_null ()) {
1612 const std::string innerName = innerPrecName ();
1613 TEUCHOS_TEST_FOR_EXCEPTION(
1614 innerName == "INVALID", std::logic_error,
1615 "Ifpack2::AdditiveSchwarz::initialize: AdditiveSchwarz doesn't "
1616 "know how to create an instance of your LocalInverseType \""
1617 << Teuchos::TypeNameTraits<LocalInverseType>::name () << "\". "
1618 "Please talk to the Ifpack2 developers for details.");
1619
1620 TEUCHOS_TEST_FOR_EXCEPTION(
1621 innerName == "CUSTOM", std::runtime_error, "Ifpack2::AdditiveSchwarz::"
1622 "initialize: If the \"inner preconditioner name\" parameter (or any "
1623 "alias thereof) has the value \"CUSTOM\", then you must first call "
1624 "setInnerPreconditioner with a nonnull inner preconditioner input before "
1625 "you may call initialize().");
1626
1627 // FIXME (mfh 26 Aug 2015) Once we fix Bug 6392, the following
1628 // three lines of code can and SHOULD go away.
1629 if (! Trilinos::Details::Impl::registeredSomeLinearSolverFactory ("Ifpack2")) {
1631 }
1632
1633 // FIXME (mfh 26 Aug 2015) Provide the capability to get inner
1634 // solvers from packages other than Ifpack2.
1635 typedef typename MV::mag_type MT;
1636 RCP<inner_solver_type> innerPrec =
1637 Trilinos::Details::getLinearSolver<MV, OP, MT> ("Ifpack2", innerName);
1638 TEUCHOS_TEST_FOR_EXCEPTION(
1639 innerPrec.is_null (), std::logic_error,
1640 "Ifpack2::AdditiveSchwarz::setup: Failed to create inner preconditioner "
1641 "with name \"" << innerName << "\".");
1642 innerPrec->setMatrix (innerMatrix_);
1643
1644 // Extract and apply the sublist of parameters to give to the
1645 // inner solver, if there is such a sublist of parameters.
1646 std::pair<Teuchos::ParameterList, bool> result = innerPrecParams ();
1647 if (result.second) {
1648 // FIXME (mfh 26 Aug 2015) We don't really want to use yet
1649 // another deep copy of the ParameterList here.
1650 innerPrec->setParameters (rcp (new ParameterList (result.first)));
1651 }
1652 Inverse_ = innerPrec; // "Commit" the inner solver.
1653 }
1654 else if (Inverse_->getMatrix ().getRawPtr () != innerMatrix_.getRawPtr ()) {
1655 // The new inner matrix is different from the inner
1656 // preconditioner's current matrix, so give the inner
1657 // preconditioner the new inner matrix.
1658 Inverse_->setMatrix (innerMatrix_);
1659 }
1660 TEUCHOS_TEST_FOR_EXCEPTION(
1661 Inverse_.is_null (), std::logic_error, "Ifpack2::AdditiveSchwarz::"
1662 "setup: Inverse_ is null right after we were supposed to have created it."
1663 " Please report this bug to the Ifpack2 developers.");
1664
1665 // We don't have to call setInnerPreconditioner() here, because we
1666 // had the inner matrix (innerMatrix_) before creation of the inner
1667 // preconditioner. Calling setInnerPreconditioner here would be
1668 // legal, but it would require an unnecessary reset of the inner
1669 // preconditioner (i.e., calling initialize() and compute() again).
1670}
1671
1672
1673template<class MatrixType, class LocalInverseType>
1678 node_type> >& innerPrec)
1679{
1680 if (! innerPrec.is_null ()) {
1681 // Make sure that the new inner solver knows how to have its matrix changed.
1682 typedef Details::CanChangeMatrix<row_matrix_type> can_change_type;
1683 can_change_type* innerSolver = dynamic_cast<can_change_type*> (&*innerPrec);
1684 TEUCHOS_TEST_FOR_EXCEPTION(
1685 innerSolver == NULL, std::invalid_argument, "Ifpack2::AdditiveSchwarz::"
1686 "setInnerPreconditioner: The input preconditioner does not implement the "
1687 "setMatrix() feature. Only input preconditioners that inherit from "
1688 "Ifpack2::Details::CanChangeMatrix implement this feature.");
1689
1690 // If users provide an inner solver, we assume that
1691 // AdditiveSchwarz's current inner solver parameters no longer
1692 // apply. (In fact, we will remove those parameters from
1693 // AdditiveSchwarz's current list below.) Thus, we do /not/ apply
1694 // the current sublist of inner solver parameters to the input
1695 // inner solver.
1696
1697 // mfh 03 Jan 2014: Thanks to Paul Tsuji for pointing out that
1698 // it's perfectly legal for innerMatrix_ to be null here. This
1699 // can happen if initialize() has not been called yet. For
1700 // example, when Ifpack2::Factory creates an AdditiveSchwarz
1701 // instance, it calls setInnerPreconditioner() without first
1702 // calling initialize().
1703
1704 // Give the local matrix to the new inner solver.
1705 if(auto asf = Teuchos::rcp_dynamic_cast<Details::AdditiveSchwarzFilter<MatrixType>>(innerMatrix_))
1706 innerSolver->setMatrix (asf->getFilteredMatrix());
1707 else
1708 innerSolver->setMatrix (innerMatrix_);
1709
1710 // If the user previously specified a parameter for the inner
1711 // preconditioner's type, then clear out that parameter and its
1712 // associated sublist. Replace the inner preconditioner's type with
1713 // "CUSTOM", to make it obvious that AdditiveSchwarz's ParameterList
1714 // does not necessarily describe the current inner preconditioner.
1715 // We have to remove all allowed aliases of "inner preconditioner
1716 // name" before we may set it to "CUSTOM". Users may also set this
1717 // parameter to "CUSTOM" themselves, but this is not required.
1718 removeInnerPrecName ();
1719 removeInnerPrecParams ();
1720 List_.set ("inner preconditioner name", "CUSTOM");
1721
1722 // Bring the new inner solver's current status (initialized or
1723 // computed) in line with AdditiveSchwarz's current status.
1724 if (isInitialized ()) {
1725 innerPrec->initialize ();
1726 }
1727 if (isComputed ()) {
1728 innerPrec->compute ();
1729 }
1730 }
1731
1732 // If the new inner solver is null, we don't change the initialized
1733 // or computed status of AdditiveSchwarz. That way, AdditiveSchwarz
1734 // won't have to recompute innerMatrix_ if the inner solver changes.
1735 // This does introduce a new error condition in compute() and
1736 // apply(), but that's OK.
1737
1738 // Set the new inner solver.
1740 global_ordinal_type, node_type> inner_solver_impl_type;
1741 Inverse_ = Teuchos::rcp (new inner_solver_impl_type (innerPrec, "CUSTOM"));
1742}
1743
1744template<class MatrixType, class LocalInverseType>
1746setMatrix (const Teuchos::RCP<const row_matrix_type>& A)
1747{
1748 // Don't set the matrix unless it is different from the current one.
1749 if (A.getRawPtr () != Matrix_.getRawPtr ()) {
1750 IsInitialized_ = false;
1751 IsComputed_ = false;
1752
1753 // Reset all the state computed in initialize() and compute().
1754 OverlappingMatrix_ = Teuchos::null;
1755 ReorderedLocalizedMatrix_ = Teuchos::null;
1756 innerMatrix_ = Teuchos::null;
1757 SingletonMatrix_ = Teuchos::null;
1758 localMap_ = Teuchos::null;
1759 overlapping_B_.reset (nullptr);
1760 overlapping_Y_.reset (nullptr);
1761 R_.reset (nullptr);
1762 C_.reset (nullptr);
1763 DistributedImporter_ = Teuchos::null;
1764
1765 Matrix_ = A;
1766 }
1767}
1768
1769} // namespace Ifpack2
1770
1771// NOTE (mfh 26 Aug 2015) There's no need to instantiate for CrsMatrix
1772// too. All Ifpack2 preconditioners can and should do dynamic casts
1773// internally, if they need a type more specific than RowMatrix.
1774#define IFPACK2_ADDITIVESCHWARZ_INSTANT(S,LO,GO,N) \
1775 template class Ifpack2::AdditiveSchwarz< Tpetra::RowMatrix<S, LO, GO, N> >;
1776
1777#endif // IFPACK2_ADDITIVESCHWARZ_DECL_HPP
1778
void registerLinearSolverFactory()
Register Ifpack2's LinearSolverFactory with the central repository, for all enabled combinations of t...
Definition Ifpack2_Details_registerLinearSolverFactory.cpp:68
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:296
typename MatrixType::local_ordinal_type local_ordinal_type
The type of local indices in the input MatrixType.
Definition Ifpack2_AdditiveSchwarz_decl.hpp:317
std::string description() const
Return a simple one-line description of this object.
Definition Ifpack2_AdditiveSchwarz_def.hpp:1207
virtual bool isInitialized() const
Returns true if the preconditioner has been successfully initialized, false otherwise.
Definition Ifpack2_AdditiveSchwarz_def.hpp:1084
virtual int getOverlapLevel() const
Returns the level of overlap.
Definition Ifpack2_AdditiveSchwarz_def.hpp:1379
Teuchos::RCP< const Teuchos::ParameterList > getValidParameters() const
Get a list of the preconditioner's default parameters.
Definition Ifpack2_AdditiveSchwarz_def.hpp:961
typename MatrixType::global_ordinal_type global_ordinal_type
The type of global indices in the input MatrixType.
Definition Ifpack2_AdditiveSchwarz_decl.hpp:320
virtual int getNumCompute() const
Returns the number of calls to compute().
Definition Ifpack2_AdditiveSchwarz_def.hpp:1172
virtual int getNumApply() const
Returns the number of calls to apply().
Definition Ifpack2_AdditiveSchwarz_def.hpp:1179
virtual double getComputeTime() const
Returns the time spent in compute().
Definition Ifpack2_AdditiveSchwarz_def.hpp:1193
virtual double getApplyTime() const
Returns the time spent in apply().
Definition Ifpack2_AdditiveSchwarz_def.hpp:1200
virtual void setMatrix(const Teuchos::RCP< const row_matrix_type > &A)
Change the matrix to be preconditioned.
Definition Ifpack2_AdditiveSchwarz_def.hpp:1746
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
void setParameterList(const Teuchos::RCP< Teuchos::ParameterList > &plist)
Set the preconditioner's parameters.
Definition Ifpack2_AdditiveSchwarz_def.hpp:765
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:1675
virtual double getInitializeTime() const
Returns the time spent in initialize().
Definition Ifpack2_AdditiveSchwarz_def.hpp:1186
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 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 void compute()
Computes all (coefficient) data necessary to apply the preconditioner.
Definition Ifpack2_AdditiveSchwarz_def.hpp:1091
virtual std::ostream & print(std::ostream &os) const
Prints basic information on iostream. This function is used by operator<<.
Definition Ifpack2_AdditiveSchwarz_def.hpp:1369
typename MatrixType::scalar_type scalar_type
The type of the entries of the input MatrixType.
Definition Ifpack2_AdditiveSchwarz_decl.hpp:314
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 void setParameters(const Teuchos::ParameterList &plist)
Set the preconditioner's parameters.
Definition Ifpack2_AdditiveSchwarz_def.hpp:752
virtual Teuchos::RCP< const row_matrix_type > getMatrix() const
The input matrix.
Definition Ifpack2_AdditiveSchwarz_def.hpp:287
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
virtual bool isComputed() const
Returns true if the preconditioner has been successfully computed, false otherwise.
Definition Ifpack2_AdditiveSchwarz_def.hpp:1158
virtual int getNumInitialize() const
Returns the number of calls to initialize().
Definition Ifpack2_AdditiveSchwarz_def.hpp:1165
AdditiveSchwarz(const Teuchos::RCP< const row_matrix_type > &A)
Constructor that takes a matrix.
Definition Ifpack2_AdditiveSchwarz_def.hpp:247
Mix-in interface for preconditioners that can change their matrix after construction.
Definition Ifpack2_Details_CanChangeMatrix.hpp:93
Ifpack2's implementation of Trilinos::Details::LinearSolver interface.
Definition Ifpack2_Details_LinearSolver_decl.hpp:110
Access only local rows and columns of a sparse matrix.
Definition Ifpack2_LocalFilter_decl.hpp:163
Sparse matrix (Tpetra::RowMatrix subclass) with ghost rows.
Definition Ifpack2_OverlappingRowMatrix_decl.hpp:59
Interface for all Ifpack2 preconditioners.
Definition Ifpack2_Preconditioner.hpp:108
Wraps a Tpetra::RowMatrix in a filter that reorders local rows and columns.
Definition Ifpack2_ReorderFilter_decl.hpp:70
Filter based on matrix entries.
Definition Ifpack2_SingletonFilter_decl.hpp:65
Preconditioners and smoothers for Tpetra sparse matrices.
Definition Ifpack2_AdditiveSchwarz_decl.hpp:74
void getValidParameters(Teuchos::ParameterList &params)
Fills a list which contains all the parameters possibly used by Ifpack2.
Definition Ifpack2_Parameters.cpp:51