319 computedLambdaMin_ (
STS::nan ()),
320 lambdaMaxForApply_ (
STS::nan ()),
321 boostFactor_ (static_cast<
MT> (1.1)),
322 lambdaMinForApply_ (
STS::nan ()),
323 eigRatioForApply_ (
STS::nan ()),
324 userLambdaMax_ (
STS::nan ()),
325 userLambdaMin_ (
STS::nan ()),
326 userEigRatio_ (Teuchos::as<
ST> (30)),
327 minDiagVal_ (
STS::eps ()),
330 eigRelTolerance_(Teuchos::ScalarTraits<
MT>::zero ()),
331 eigKeepVectors_(false),
332 eigenAnalysisType_(
"power method"),
333 eigNormalizationFreq_(1),
334 zeroStartingSolution_ (true),
335 assumeMatrixUnchanged_ (false),
336 chebyshevAlgorithm_(
"first"),
337 computeMaxResNorm_ (false),
338 computeSpectralRadius_(true),
339 ckUseNativeSpMV_(false),
342 checkConstructorInput ();
346template<
class ScalarType,
class MV>
353 using Teuchos::rcp_const_cast;
365 const ST defaultLambdaMax = STS::nan ();
366 const ST defaultLambdaMin = STS::nan ();
373 const ST defaultEigRatio = Teuchos::as<ST> (30);
374 const MT defaultBoostFactor =
static_cast<MT> (1.1);
375 const ST defaultMinDiagVal = STS::eps ();
376 const int defaultNumIters = 1;
377 const int defaultEigMaxIters = 10;
378 const MT defaultEigRelTolerance = Teuchos::ScalarTraits<MT>::zero ();
379 const bool defaultEigKeepVectors =
false;
380 const int defaultEigNormalizationFreq = 1;
381 const bool defaultZeroStartingSolution =
true;
382 const bool defaultAssumeMatrixUnchanged =
false;
383 const std::string defaultChebyshevAlgorithm =
"first";
384 const bool defaultComputeMaxResNorm =
false;
385 const bool defaultComputeSpectralRadius =
true;
386 const bool defaultCkUseNativeSpMV =
false;
387 const bool defaultDebug =
false;
393 RCP<const V> userInvDiagCopy;
394 ST lambdaMax = defaultLambdaMax;
395 ST lambdaMin = defaultLambdaMin;
396 ST eigRatio = defaultEigRatio;
397 MT boostFactor = defaultBoostFactor;
398 ST minDiagVal = defaultMinDiagVal;
399 int numIters = defaultNumIters;
400 int eigMaxIters = defaultEigMaxIters;
401 MT eigRelTolerance = defaultEigRelTolerance;
402 bool eigKeepVectors = defaultEigKeepVectors;
403 int eigNormalizationFreq = defaultEigNormalizationFreq;
404 bool zeroStartingSolution = defaultZeroStartingSolution;
405 bool assumeMatrixUnchanged = defaultAssumeMatrixUnchanged;
406 std::string chebyshevAlgorithm = defaultChebyshevAlgorithm;
407 bool computeMaxResNorm = defaultComputeMaxResNorm;
408 bool computeSpectralRadius = defaultComputeSpectralRadius;
409 bool ckUseNativeSpMV = defaultCkUseNativeSpMV;
410 bool debug = defaultDebug;
417 if (plist.isType<
bool> (
"debug")) {
418 debug = plist.get<
bool> (
"debug");
420 else if (plist.isType<
int> (
"debug")) {
421 const int debugInt = plist.get<
bool> (
"debug");
422 debug = debugInt != 0;
435 const char opInvDiagLabel[] =
"chebyshev: operator inv diagonal";
436 if (plist.isParameter (opInvDiagLabel)) {
438 RCP<const V> userInvDiag;
440 if (plist.isType<
const V*> (opInvDiagLabel)) {
441 const V* rawUserInvDiag =
442 plist.get<
const V*> (opInvDiagLabel);
444 userInvDiag = rcp (rawUserInvDiag,
false);
446 else if (plist.isType<
const V*> (opInvDiagLabel)) {
447 V* rawUserInvDiag = plist.get<
V*> (opInvDiagLabel);
449 userInvDiag = rcp (
const_cast<const V*
> (rawUserInvDiag),
false);
451 else if (plist.isType<RCP<const V>> (opInvDiagLabel)) {
452 userInvDiag = plist.get<RCP<const V> > (opInvDiagLabel);
454 else if (plist.isType<RCP<V>> (opInvDiagLabel)) {
455 RCP<V> userInvDiagNonConst =
456 plist.get<RCP<V> > (opInvDiagLabel);
457 userInvDiag = rcp_const_cast<const V> (userInvDiagNonConst);
459 else if (plist.isType<
const V> (opInvDiagLabel)) {
460 const V& userInvDiagRef = plist.get<
const V> (opInvDiagLabel);
461 userInvDiagCopy = rcp (
new V (userInvDiagRef, Teuchos::Copy));
462 userInvDiag = userInvDiagCopy;
464 else if (plist.isType<
V> (opInvDiagLabel)) {
465 V& userInvDiagNonConstRef = plist.get<
V> (opInvDiagLabel);
466 const V& userInvDiagRef =
const_cast<const V&
> (userInvDiagNonConstRef);
467 userInvDiagCopy = rcp (
new V (userInvDiagRef, Teuchos::Copy));
468 userInvDiag = userInvDiagCopy;
478 if (! userInvDiag.is_null () && userInvDiagCopy.is_null ()) {
479 userInvDiagCopy = rcp (
new V (*userInvDiag, Teuchos::Copy));
489 if (plist.isParameter (
"chebyshev: use native spmv"))
490 ckUseNativeSpMV = plist.get(
"chebyshev: use native spmv", ckUseNativeSpMV);
495 if (plist.isParameter (
"chebyshev: max eigenvalue")) {
496 if (plist.isType<
double>(
"chebyshev: max eigenvalue"))
497 lambdaMax = plist.get<
double> (
"chebyshev: max eigenvalue");
499 lambdaMax = plist.get<
ST> (
"chebyshev: max eigenvalue");
500 TEUCHOS_TEST_FOR_EXCEPTION(
501 STS::isnaninf (lambdaMax), std::invalid_argument,
502 "Ifpack2::Chebyshev::setParameters: \"chebyshev: max eigenvalue\" "
503 "parameter is NaN or Inf. This parameter is optional, but if you "
504 "choose to supply it, it must have a finite value.");
506 if (plist.isParameter (
"chebyshev: min eigenvalue")) {
507 if (plist.isType<
double>(
"chebyshev: min eigenvalue"))
508 lambdaMin = plist.get<
double> (
"chebyshev: min eigenvalue");
510 lambdaMin = plist.get<
ST> (
"chebyshev: min eigenvalue");
511 TEUCHOS_TEST_FOR_EXCEPTION(
512 STS::isnaninf (lambdaMin), std::invalid_argument,
513 "Ifpack2::Chebyshev::setParameters: \"chebyshev: min eigenvalue\" "
514 "parameter is NaN or Inf. This parameter is optional, but if you "
515 "choose to supply it, it must have a finite value.");
519 if (plist.isParameter (
"smoother: Chebyshev alpha")) {
520 if (plist.isType<
double>(
"smoother: Chebyshev alpha"))
521 eigRatio = plist.get<
double> (
"smoother: Chebyshev alpha");
523 eigRatio = plist.get<
ST> (
"smoother: Chebyshev alpha");
526 eigRatio = plist.get (
"chebyshev: ratio eigenvalue", eigRatio);
527 TEUCHOS_TEST_FOR_EXCEPTION(
528 STS::isnaninf (eigRatio), std::invalid_argument,
529 "Ifpack2::Chebyshev::setParameters: \"chebyshev: ratio eigenvalue\" "
530 "parameter (also called \"smoother: Chebyshev alpha\") is NaN or Inf. "
531 "This parameter is optional, but if you choose to supply it, it must have "
538 TEUCHOS_TEST_FOR_EXCEPTION(
539 STS::real (eigRatio) < STS::real (STS::one ()),
540 std::invalid_argument,
541 "Ifpack2::Chebyshev::setParameters: \"chebyshev: ratio eigenvalue\""
542 "parameter (also called \"smoother: Chebyshev alpha\") must be >= 1, "
543 "but you supplied the value " << eigRatio <<
".");
548 const char paramName[] =
"chebyshev: boost factor";
550 if (plist.isParameter (paramName)) {
551 if (plist.isType<
MT> (paramName)) {
552 boostFactor = plist.get<
MT> (paramName);
554 else if (! std::is_same<double, MT>::value &&
555 plist.isType<
double> (paramName)) {
556 const double dblBF = plist.get<
double> (paramName);
557 boostFactor =
static_cast<MT> (dblBF);
560 TEUCHOS_TEST_FOR_EXCEPTION
561 (
true, std::invalid_argument,
562 "Ifpack2::Chebyshev::setParameters: \"chebyshev: boost factor\""
563 "parameter must have type magnitude_type (MT) or double.");
573 plist.set (paramName, defaultBoostFactor);
575 TEUCHOS_TEST_FOR_EXCEPTION
576 (boostFactor < Teuchos::ScalarTraits<MT>::one (), std::invalid_argument,
577 "Ifpack2::Chebyshev::setParameters: \"" << paramName <<
"\" parameter "
578 "must be >= 1, but you supplied the value " << boostFactor <<
".");
582 minDiagVal = plist.get (
"chebyshev: min diagonal value", minDiagVal);
583 TEUCHOS_TEST_FOR_EXCEPTION(
584 STS::isnaninf (minDiagVal), std::invalid_argument,
585 "Ifpack2::Chebyshev::setParameters: \"chebyshev: min diagonal value\" "
586 "parameter is NaN or Inf. This parameter is optional, but if you choose "
587 "to supply it, it must have a finite value.");
590 if (plist.isParameter (
"smoother: sweeps")) {
591 numIters = plist.get<
int> (
"smoother: sweeps");
593 if (plist.isParameter (
"relaxation: sweeps")) {
594 numIters = plist.get<
int> (
"relaxation: sweeps");
596 numIters = plist.get (
"chebyshev: degree", numIters);
597 TEUCHOS_TEST_FOR_EXCEPTION(
598 numIters < 0, std::invalid_argument,
599 "Ifpack2::Chebyshev::setParameters: \"chebyshev: degree\" parameter (also "
600 "called \"smoother: sweeps\" or \"relaxation: sweeps\") must be a "
601 "nonnegative integer. You gave a value of " << numIters <<
".");
604 if (plist.isParameter (
"eigen-analysis: iterations")) {
605 eigMaxIters = plist.get<
int> (
"eigen-analysis: iterations");
607 eigMaxIters = plist.get (
"chebyshev: eigenvalue max iterations", eigMaxIters);
608 TEUCHOS_TEST_FOR_EXCEPTION(
609 eigMaxIters < 0, std::invalid_argument,
610 "Ifpack2::Chebyshev::setParameters: \"chebyshev: eigenvalue max iterations"
611 "\" parameter (also called \"eigen-analysis: iterations\") must be a "
612 "nonnegative integer. You gave a value of " << eigMaxIters <<
".");
614 if (plist.isType<
double>(
"chebyshev: eigenvalue relative tolerance"))
615 eigRelTolerance = Teuchos::as<MT>(plist.get<
double> (
"chebyshev: eigenvalue relative tolerance"));
616 else if (plist.isType<
MT>(
"chebyshev: eigenvalue relative tolerance"))
617 eigRelTolerance = plist.get<
MT> (
"chebyshev: eigenvalue relative tolerance");
618 else if (plist.isType<
ST>(
"chebyshev: eigenvalue relative tolerance"))
619 eigRelTolerance = Teuchos::ScalarTraits<ST>::magnitude(plist.get<
ST> (
"chebyshev: eigenvalue relative tolerance"));
621 eigKeepVectors = plist.get (
"chebyshev: eigenvalue keep vectors", eigKeepVectors);
623 eigNormalizationFreq = plist.get (
"chebyshev: eigenvalue normalization frequency", eigNormalizationFreq);
624 TEUCHOS_TEST_FOR_EXCEPTION(
625 eigNormalizationFreq < 0, std::invalid_argument,
626 "Ifpack2::Chebyshev::setParameters: \"chebyshev: eigenvalue normalization frequency"
627 "\" parameter must be a "
628 "nonnegative integer. You gave a value of " << eigNormalizationFreq <<
".")
630 zeroStartingSolution = plist.get (
"chebyshev: zero starting solution",
631 zeroStartingSolution);
632 assumeMatrixUnchanged = plist.get (
"chebyshev: assume matrix does not change",
633 assumeMatrixUnchanged);
637 if (plist.isParameter (
"chebyshev: algorithm")) {
638 chebyshevAlgorithm = plist.get<std::string> (
"chebyshev: algorithm");
639 TEUCHOS_TEST_FOR_EXCEPTION(
640 chebyshevAlgorithm !=
"first" &&
641 chebyshevAlgorithm !=
"textbook" &&
642 chebyshevAlgorithm !=
"fourth" &&
643 chebyshevAlgorithm !=
"opt_fourth",
644 std::invalid_argument,
645 "Ifpack2::Chebyshev: Ifpack2 only supports \"first\", \"textbook\", \"fourth\", and \"opt_fourth\", for \"chebyshev: algorithm\".");
648#ifdef IFPACK2_ENABLE_DEPRECATED_CODE
651 if (!plist.isParameter (
"chebyshev: algorithm")) {
652 if (plist.isParameter (
"chebyshev: textbook algorithm")) {
653 const bool textbookAlgorithm = plist.get<
bool> (
"chebyshev: textbook algorithm");
654 if(textbookAlgorithm){
655 chebyshevAlgorithm =
"textbook";
657 chebyshevAlgorithm =
"first";
663 if (plist.isParameter (
"chebyshev: compute max residual norm")) {
664 computeMaxResNorm = plist.get<
bool> (
"chebyshev: compute max residual norm");
666 if (plist.isParameter (
"chebyshev: compute spectral radius")) {
667 computeSpectralRadius = plist.get<
bool> (
"chebyshev: compute spectral radius");
675 TEUCHOS_TEST_FOR_EXCEPTION
676 (plist.isType<
bool> (
"chebyshev: use block mode") &&
677 ! plist.get<
bool> (
"chebyshev: use block mode"),
678 std::invalid_argument,
679 "Ifpack2::Chebyshev requires that if you set \"chebyshev: use "
680 "block mode\" at all, you must set it to false. "
681 "Ifpack2::Chebyshev does not implement Ifpack's block mode.");
682 TEUCHOS_TEST_FOR_EXCEPTION
683 (plist.isType<
bool> (
"chebyshev: solve normal equations") &&
684 ! plist.get<
bool> (
"chebyshev: solve normal equations"),
685 std::invalid_argument,
686 "Ifpack2::Chebyshev does not and will never implement the Ifpack "
687 "parameter \"chebyshev: solve normal equations\". If you want to "
688 "solve the normal equations, construct a Tpetra::Operator that "
689 "implements A^* A, and use Chebyshev to solve A^* A x = A^* b.");
697 std::string eigenAnalysisType (
"power-method");
698 if (plist.isParameter (
"eigen-analysis: type")) {
699 eigenAnalysisType = plist.get<std::string> (
"eigen-analysis: type");
700 TEUCHOS_TEST_FOR_EXCEPTION(
701 eigenAnalysisType !=
"power-method" &&
702 eigenAnalysisType !=
"power method" &&
703 eigenAnalysisType !=
"cg",
704 std::invalid_argument,
705 "Ifpack2::Chebyshev: Ifpack2 only supports \"power method\" and \"cg\" for \"eigen-analysis: type\".");
709 userInvDiag_ = userInvDiagCopy;
710 userLambdaMax_ = lambdaMax;
711 userLambdaMin_ = lambdaMin;
712 userEigRatio_ = eigRatio;
713 boostFactor_ =
static_cast<MT> (boostFactor);
714 minDiagVal_ = minDiagVal;
715 numIters_ = numIters;
716 eigMaxIters_ = eigMaxIters;
717 eigRelTolerance_ = eigRelTolerance;
718 eigKeepVectors_ = eigKeepVectors;
719 eigNormalizationFreq_ = eigNormalizationFreq;
720 eigenAnalysisType_ = eigenAnalysisType;
721 zeroStartingSolution_ = zeroStartingSolution;
722 assumeMatrixUnchanged_ = assumeMatrixUnchanged;
723 chebyshevAlgorithm_ = chebyshevAlgorithm;
724 computeMaxResNorm_ = computeMaxResNorm;
725 computeSpectralRadius_ = computeSpectralRadius;
726 ckUseNativeSpMV_ = ckUseNativeSpMV;
732 if (A_.is_null () || A_->getComm ().is_null ()) {
738 myRank = A_->getComm ()->getRank ();
742 out_ = Teuchos::getFancyOStream (Teuchos::rcpFromRef (std::cerr));
745 using Teuchos::oblackholestream;
746 RCP<oblackholestream> blackHole (
new oblackholestream ());
747 out_ = Teuchos::getFancyOStream (blackHole);
752 out_ = Teuchos::null;
757template<
class ScalarType,
class MV>
759Chebyshev<ScalarType, MV>::reset ()
763 diagOffsets_ = offsets_type ();
764 savedDiagOffsets_ =
false;
766 computedLambdaMax_ = STS::nan ();
767 computedLambdaMin_ = STS::nan ();
768 eigVector_ = Teuchos::null;
769 eigVector2_ = Teuchos::null;
773template<
class ScalarType,
class MV>
776setMatrix (
const Teuchos::RCP<const row_matrix_type>& A)
778 if (A.getRawPtr () != A_.getRawPtr ()) {
779 if (! assumeMatrixUnchanged_) {
791 if (A.is_null () || A->getComm ().is_null ()) {
797 myRank = A->getComm ()->getRank ();
801 out_ = Teuchos::getFancyOStream (Teuchos::rcpFromRef (std::cerr));
804 Teuchos::RCP<Teuchos::oblackholestream> blackHole (
new Teuchos::oblackholestream ());
805 out_ = Teuchos::getFancyOStream (blackHole);
810 out_ = Teuchos::null;
815template<
class ScalarType,
class MV>
824 typedef Tpetra::CrsMatrix<
typename MV::scalar_type,
825 typename MV::local_ordinal_type,
826 typename MV::global_ordinal_type,
827 typename MV::node_type> crs_matrix_type;
829 TEUCHOS_TEST_FOR_EXCEPTION(
830 A_.is_null (), std::runtime_error,
"Ifpack2::Chebyshev::compute: The input "
831 "matrix A is null. Please call setMatrix() with a nonnull input matrix "
832 "before calling this method.");
847 if (userInvDiag_.is_null ()) {
848 Teuchos::RCP<const crs_matrix_type> A_crsMat =
849 Teuchos::rcp_dynamic_cast<const crs_matrix_type> (A_);
851 if (! A_crsMat.is_null () && A_crsMat->isFillComplete ()) {
853 const size_t lclNumRows = A_crsMat->getLocalNumRows ();
854 if (diagOffsets_.extent (0) < lclNumRows) {
855 diagOffsets_ = offsets_type ();
856 diagOffsets_ = offsets_type (
"offsets", lclNumRows);
858 A_crsMat->getCrsGraph ()->getLocalDiagOffsets (diagOffsets_);
859 savedDiagOffsets_ =
true;
860 D_ = makeInverseDiagonal (*A_,
true);
863 D_ = makeInverseDiagonal (*A_);
866 else if (! assumeMatrixUnchanged_) {
867 if (! A_crsMat.is_null () && A_crsMat->isFillComplete ()) {
870 if (! savedDiagOffsets_) {
871 const size_t lclNumRows = A_crsMat->getLocalNumRows ();
872 if (diagOffsets_.extent (0) < lclNumRows) {
873 diagOffsets_ = offsets_type ();
874 diagOffsets_ = offsets_type (
"offsets", lclNumRows);
876 A_crsMat->getCrsGraph ()->getLocalDiagOffsets (diagOffsets_);
877 savedDiagOffsets_ =
true;
880 D_ = makeInverseDiagonal (*A_,
true);
883 D_ = makeInverseDiagonal (*A_);
888 D_ = makeRangeMapVectorConst (userInvDiag_);
892 const bool computedEigenvalueEstimates =
893 STS::isnaninf (computedLambdaMax_) || STS::isnaninf (computedLambdaMin_);
903 if (! assumeMatrixUnchanged_ ||
904 (! computedEigenvalueEstimates && STS::isnaninf (userLambdaMax_))) {
905 ST computedLambdaMax;
906 if ((eigenAnalysisType_ ==
"power method") || (eigenAnalysisType_ ==
"power-method")) {
908 if (eigVector_.is_null()) {
909 x = Teuchos::rcp(
new V(A_->getDomainMap ()));
917 if (eigVector2_.is_null()) {
918 y = rcp(
new V(A_->getRangeMap ()));
924 Teuchos::RCP<Teuchos::FancyOStream> stream = (debug_ ? out_ : Teuchos::null);
926 eigRelTolerance_, eigNormalizationFreq_, stream,
927 computeSpectralRadius_);
930 computedLambdaMax = cgMethod (*A_, *D_, eigMaxIters_);
932 TEUCHOS_TEST_FOR_EXCEPTION(
933 STS::isnaninf (computedLambdaMax),
935 "Ifpack2::Chebyshev::compute: Estimation of the max eigenvalue "
936 "of D^{-1} A failed, by producing Inf or NaN. This probably means that "
937 "the matrix contains Inf or NaN values, or that it is badly scaled.");
938 TEUCHOS_TEST_FOR_EXCEPTION(
939 STS::isnaninf (userEigRatio_),
941 "Ifpack2::Chebyshev::compute: userEigRatio_ is Inf or NaN."
942 << endl <<
"This should be impossible." << endl <<
943 "Please report this bug to the Ifpack2 developers.");
949 const ST computedLambdaMin = computedLambdaMax / userEigRatio_;
952 computedLambdaMax_ = computedLambdaMax;
953 computedLambdaMin_ = computedLambdaMin;
955 TEUCHOS_TEST_FOR_EXCEPTION(
956 STS::isnaninf (userLambdaMax_) && STS::isnaninf (computedLambdaMax_),
958 "Ifpack2::Chebyshev::compute: " << endl <<
959 "Both userLambdaMax_ and computedLambdaMax_ are Inf or NaN."
960 << endl <<
"This should be impossible." << endl <<
961 "Please report this bug to the Ifpack2 developers.");
969 lambdaMaxForApply_ = STS::isnaninf (userLambdaMax_) ? computedLambdaMax_ : userLambdaMax_;
982 lambdaMinForApply_ = lambdaMaxForApply_ / userEigRatio_;
983 eigRatioForApply_ = userEigRatio_;
985 if (chebyshevAlgorithm_ ==
"first") {
988 const ST one = Teuchos::as<ST> (1);
991 if (STS::magnitude (lambdaMaxForApply_ - one) < Teuchos::as<MT> (1.0e-6)) {
992 lambdaMinForApply_ = one;
993 lambdaMaxForApply_ = lambdaMinForApply_;
994 eigRatioForApply_ = one;
1000template<
class ScalarType,
class MV>
1004 return lambdaMaxForApply_;
1008template<
class ScalarType,
class MV>
1012 const char prefix[] =
"Ifpack2::Chebyshev::apply: ";
1015 *out_ <<
"apply: " << std::endl;
1017 TEUCHOS_TEST_FOR_EXCEPTION
1018 (A_.is_null (), std::runtime_error, prefix <<
"The input matrix A is null. "
1019 " Please call setMatrix() with a nonnull input matrix, and then call "
1020 "compute(), before calling this method.");
1021 TEUCHOS_TEST_FOR_EXCEPTION
1022 (STS::isnaninf (lambdaMaxForApply_), std::runtime_error,
1023 prefix <<
"There is no estimate for the max eigenvalue."
1024 << std::endl << computeBeforeApplyReminder);
1025 TEUCHOS_TEST_FOR_EXCEPTION
1026 (STS::isnaninf (lambdaMinForApply_), std::runtime_error,
1027 prefix <<
"There is no estimate for the min eigenvalue."
1028 << std::endl << computeBeforeApplyReminder);
1029 TEUCHOS_TEST_FOR_EXCEPTION
1030 (STS::isnaninf (eigRatioForApply_), std::runtime_error,
1031 prefix <<
"There is no estimate for the ratio of the max "
1032 "eigenvalue to the min eigenvalue."
1033 << std::endl << computeBeforeApplyReminder);
1034 TEUCHOS_TEST_FOR_EXCEPTION
1035 (D_.is_null (), std::runtime_error, prefix <<
"The vector of inverse "
1036 "diagonal entries of the matrix has not yet been computed."
1037 << std::endl << computeBeforeApplyReminder);
1039 if (chebyshevAlgorithm_ ==
"fourth" || chebyshevAlgorithm_ ==
"opt_fourth") {
1040 fourthKindApplyImpl (*A_, B, X, numIters_, lambdaMaxForApply_, *D_);
1042 else if (chebyshevAlgorithm_ ==
"textbook") {
1043 textbookApplyImpl (*A_, B, X, numIters_, lambdaMaxForApply_,
1044 lambdaMinForApply_, eigRatioForApply_, *D_);
1047 ifpackApplyImpl (*A_, B, X, numIters_, lambdaMaxForApply_,
1048 lambdaMinForApply_, eigRatioForApply_, *D_);
1051 if (computeMaxResNorm_ && B.getNumVectors () > 0) {
1052 MV R (B.getMap (), B.getNumVectors ());
1053 computeResidual (R, B, *A_, X);
1054 Teuchos::Array<MT> norms (B.getNumVectors ());
1056 return *std::max_element (norms.begin (), norms.end ());
1059 return Teuchos::ScalarTraits<MT>::zero ();
1063template<
class ScalarType,
class MV>
1066print (std::ostream& out)
1068 using Teuchos::rcpFromRef;
1069 this->
describe (* (Teuchos::getFancyOStream (rcpFromRef (out))),
1070 Teuchos::VERB_MEDIUM);
1073template<
class ScalarType,
class MV>
1077 const ScalarType& alpha,
1082 solve (W, alpha, D_inv, B);
1083 Tpetra::deep_copy (X, W);
1086template<
class ScalarType,
class MV>
1090 const Teuchos::ETransp mode)
1092 Tpetra::Details::residual(A,X,B,R);
1095template <
class ScalarType,
class MV>
1097Chebyshev<ScalarType, MV>::
1098solve (MV& Z,
const V& D_inv,
const MV& R) {
1099 Z.elementWiseMultiply (STS::one(), D_inv, R, STS::zero());
1102template<
class ScalarType,
class MV>
1105solve (MV& Z,
const ST alpha,
const V& D_inv,
const MV& R) {
1106 Z.elementWiseMultiply (alpha, D_inv, R, STS::zero());
1109template<
class ScalarType,
class MV>
1110Teuchos::RCP<const typename Chebyshev<ScalarType, MV>::V>
1115 using Teuchos::rcpFromRef;
1116 using Teuchos::rcp_dynamic_cast;
1119 if (!D_.is_null() &&
1120 D_->getMap()->isSameAs(*(A.getRowMap ()))) {
1122 *out_ <<
"Reusing pre-existing vector for diagonal extraction" << std::endl;
1123 D_rowMap = Teuchos::rcp_const_cast<V>(D_);
1125 D_rowMap = Teuchos::rcp(
new V (A.getRowMap (),
false));
1127 *out_ <<
"Allocated new vector for diagonal extraction" << std::endl;
1129 if (useDiagOffsets) {
1133 typedef Tpetra::CrsMatrix<
typename MV::scalar_type,
1134 typename MV::local_ordinal_type,
1135 typename MV::global_ordinal_type,
1136 typename MV::node_type> crs_matrix_type;
1137 RCP<const crs_matrix_type> A_crsMat =
1138 rcp_dynamic_cast<const crs_matrix_type> (rcpFromRef (A));
1139 if (! A_crsMat.is_null ()) {
1140 TEUCHOS_TEST_FOR_EXCEPTION(
1141 ! savedDiagOffsets_, std::logic_error,
1142 "Ifpack2::Details::Chebyshev::makeInverseDiagonal: "
1143 "It is not allowed to call this method with useDiagOffsets=true, "
1144 "if you have not previously saved offsets of diagonal entries. "
1145 "This situation should never arise if this class is used properly. "
1146 "Please report this bug to the Ifpack2 developers.");
1147 A_crsMat->getLocalDiagCopy (*D_rowMap, diagOffsets_);
1153 A.getLocalDiagCopy (*D_rowMap);
1155 RCP<V> D_rangeMap = makeRangeMapVector (D_rowMap);
1161 bool foundNonpositiveValue =
false;
1163 auto D_lcl = D_rangeMap->getLocalViewHost (Tpetra::Access::ReadOnly);
1164 auto D_lcl_1d = Kokkos::subview (D_lcl, Kokkos::ALL (), 0);
1166 typedef typename MV::impl_scalar_type IST;
1167 typedef typename MV::local_ordinal_type LO;
1168 typedef Kokkos::ArithTraits<IST> ATS;
1169 typedef Kokkos::ArithTraits<typename ATS::mag_type> STM;
1171 const LO lclNumRows =
static_cast<LO
> (D_rangeMap->getLocalLength ());
1172 for (LO i = 0; i < lclNumRows; ++i) {
1173 if (STS::real (D_lcl_1d(i)) <= STM::zero ()) {
1174 foundNonpositiveValue =
true;
1180 using Teuchos::outArg;
1181 using Teuchos::REDUCE_MIN;
1182 using Teuchos::reduceAll;
1184 const int lclSuccess = foundNonpositiveValue ? 0 : 1;
1185 int gblSuccess = lclSuccess;
1186 if (! D_rangeMap->getMap ().is_null () && D_rangeMap->getMap ()->getComm ().is_null ()) {
1187 const Teuchos::Comm<int>& comm = * (D_rangeMap->getMap ()->getComm ());
1188 reduceAll<int, int> (comm, REDUCE_MIN, lclSuccess, outArg (gblSuccess));
1190 if (gblSuccess == 1) {
1191 *out_ <<
"makeInverseDiagonal: The matrix's diagonal entries all have "
1192 "positive real part (this is good for Chebyshev)." << std::endl;
1195 *out_ <<
"makeInverseDiagonal: The matrix's diagonal has at least one "
1196 "entry with nonpositive real part, on at least one process in the "
1197 "matrix's communicator. This is bad for Chebyshev." << std::endl;
1203 reciprocal_threshold (*D_rangeMap, minDiagVal_);
1204 return Teuchos::rcp_const_cast<const V> (D_rangeMap);
1208template<
class ScalarType,
class MV>
1209Teuchos::RCP<const typename Chebyshev<ScalarType, MV>::V>
1215 typedef Tpetra::Export<
typename MV::local_ordinal_type,
1216 typename MV::global_ordinal_type,
1217 typename MV::node_type> export_type;
1221 TEUCHOS_TEST_FOR_EXCEPTION(
1222 A_.is_null (), std::logic_error,
"Ifpack2::Details::Chebyshev::"
1223 "makeRangeMapVector: The input matrix A is null. Please call setMatrix() "
1224 "with a nonnull input matrix before calling this method. This is probably "
1225 "a bug in Ifpack2; please report this bug to the Ifpack2 developers.");
1226 TEUCHOS_TEST_FOR_EXCEPTION(
1227 D.is_null (), std::logic_error,
"Ifpack2::Details::Chebyshev::"
1228 "makeRangeMapVector: The input Vector D is null. This is probably "
1229 "a bug in Ifpack2; please report this bug to the Ifpack2 developers.");
1231 RCP<const map_type> sourceMap = D->getMap ();
1232 RCP<const map_type> rangeMap = A_->getRangeMap ();
1233 RCP<const map_type> rowMap = A_->getRowMap ();
1235 if (rangeMap->isSameAs (*sourceMap)) {
1241 RCP<const export_type> exporter;
1245 if (sourceMap->isSameAs (*rowMap)) {
1247 exporter = A_->getGraph ()->getExporter ();
1250 exporter = rcp (
new export_type (sourceMap, rangeMap));
1253 if (exporter.is_null ()) {
1257 RCP<V> D_out = rcp (
new V (*D, Teuchos::Copy));
1258 D_out->doExport (*D, *exporter, Tpetra::ADD);
1259 return Teuchos::rcp_const_cast<const V> (D_out);
1265template<
class ScalarType,
class MV>
1266Teuchos::RCP<typename Chebyshev<ScalarType, MV>::V>
1270 using Teuchos::rcp_const_cast;
1271 return rcp_const_cast<V> (makeRangeMapVectorConst (rcp_const_cast<V> (D)));
1275template<
class ScalarType,
class MV>
1285 const V& D_inv)
const
1288 const ST myLambdaMin = lambdaMax / eigRatio;
1290 const ST zero = Teuchos::as<ST> (0);
1291 const ST one = Teuchos::as<ST> (1);
1292 const ST two = Teuchos::as<ST> (2);
1293 const ST d = (lambdaMax + myLambdaMin) / two;
1294 const ST c = (lambdaMax - myLambdaMin) / two;
1296 if (zeroStartingSolution_ && numIters > 0) {
1300 MV R (B.getMap (), B.getNumVectors (),
false);
1301 MV P (B.getMap (), B.getNumVectors (),
false);
1302 MV Z (B.getMap (), B.getNumVectors (),
false);
1304 for (
int i = 0; i < numIters; ++i) {
1305 computeResidual (R, B, A, X);
1306 solve (Z, D_inv, R);
1314 beta = alpha * (c/two) * (c/two);
1315 alpha = one / (d - beta);
1316 P.update (one, Z, beta);
1318 X.update (alpha, P, one);
1325template<
class ScalarType,
class MV>
1336 std::vector<ScalarType> betas(numIters, 1.0);
1337 if(chebyshevAlgorithm_ ==
"opt_fourth"){
1341 const ST invEig = MT(1) / (lambdaMax * boostFactor_);
1344 Teuchos::RCP<MV> Z_ptr = makeTempMultiVector (B);
1349 Teuchos::RCP<MV> X4_ptr = makeSecondTempMultiVector (B);
1353 if (! zeroStartingSolution_) {
1356 Tpetra::deep_copy (X4, X);
1358 if (ck_.is_null ()) {
1359 Teuchos::RCP<const op_type> A_op = A_;
1364 ck_->compute (Z, MT(4.0/3.0) * invEig,
const_cast<V&
> (D_inv),
1365 const_cast<MV&
> (B), X4, STS::zero());
1368 X.update (betas[0], Z, STS::one());
1372 firstIterationWithZeroStartingSolution (Z, MT(4.0/3.0) * invEig, D_inv, B, X4);
1375 X.update (betas[0], Z, STS::zero());
1378 if (numIters > 1 && ck_.is_null ()) {
1379 Teuchos::RCP<const op_type> A_op = A_;
1383 for (
int i = 1; i < numIters; ++i) {
1384 const ST zScale = (2.0 * i - 1.0) / (2.0 * i + 3.0);
1385 const ST rScale = MT((8.0 * i + 4.0) / (2.0 * i + 3.0)) * invEig;
1389 ck_->compute (Z, rScale,
const_cast<V&
> (D_inv),
1390 const_cast<MV&
> (B), (X4), zScale);
1393 X.update (betas[i], Z, STS::one());
1397template<
class ScalarType,
class MV>
1399Chebyshev<ScalarType, MV>::maxNormInf (
const MV& X) {
1400 Teuchos::Array<MT> norms (X.getNumVectors ());
1401 X.normInf (norms());
1402 return *std::max_element (norms.begin (), norms.end ());
1405template<
class ScalarType,
class MV>
1418#ifdef HAVE_IFPACK2_DEBUG
1419 const bool debug = debug_;
1421 const bool debug =
false;
1425 *out_ <<
" \\|B\\|_{\\infty} = " << maxNormInf (B) << endl;
1426 *out_ <<
" \\|X\\|_{\\infty} = " << maxNormInf (X) << endl;
1429 if (numIters <= 0) {
1432 const ST zero =
static_cast<ST
> (0.0);
1433 const ST one =
static_cast<ST
> (1.0);
1434 const ST two =
static_cast<ST
> (2.0);
1437 if (lambdaMin == one && lambdaMax == lambdaMin) {
1438 solve (X, D_inv, B);
1443 const ST alpha = lambdaMax / eigRatio;
1444 const ST beta = boostFactor_ * lambdaMax;
1445 const ST delta = two / (beta - alpha);
1446 const ST theta = (beta + alpha) / two;
1447 const ST s1 = theta * delta;
1450 *out_ <<
" alpha = " << alpha << endl
1451 <<
" beta = " << beta << endl
1452 <<
" delta = " << delta << endl
1453 <<
" theta = " << theta << endl
1454 <<
" s1 = " << s1 << endl;
1458 Teuchos::RCP<MV> W_ptr = makeTempMultiVector (B);
1462 *out_ <<
" Iteration " << 1 <<
":" << endl
1463 <<
" - \\|D\\|_{\\infty} = " << D_->normInf () << endl;
1467 if (! zeroStartingSolution_) {
1470 if (ck_.is_null ()) {
1471 Teuchos::RCP<const op_type> A_op = A_;
1476 ck_->compute (W, one/theta,
const_cast<V&
> (D_inv),
1477 const_cast<MV&
> (B), X, zero);
1481 firstIterationWithZeroStartingSolution (W, one/theta, D_inv, B, X);
1485 *out_ <<
" - \\|W\\|_{\\infty} = " << maxNormInf (W) << endl
1486 <<
" - \\|X\\|_{\\infty} = " << maxNormInf (X) << endl;
1489 if (numIters > 1 && ck_.is_null ()) {
1490 Teuchos::RCP<const op_type> A_op = A_;
1496 ST rhokp1, dtemp1, dtemp2;
1497 for (
int deg = 1; deg < numIters; ++deg) {
1499 *out_ <<
" Iteration " << deg+1 <<
":" << endl
1500 <<
" - \\|D\\|_{\\infty} = " << D_->normInf () << endl
1501 <<
" - \\|B\\|_{\\infty} = " << maxNormInf (B) << endl
1502 <<
" - \\|A\\|_{\\text{frob}} = " << A_->getFrobeniusNorm ()
1503 << endl <<
" - rhok = " << rhok << endl;
1506 rhokp1 = one / (two * s1 - rhok);
1507 dtemp1 = rhokp1 * rhok;
1508 dtemp2 = two * rhokp1 * delta;
1512 *out_ <<
" - dtemp1 = " << dtemp1 << endl
1513 <<
" - dtemp2 = " << dtemp2 << endl;
1518 ck_->compute (W, dtemp2,
const_cast<V&
> (D_inv),
1519 const_cast<MV&
> (B), (X), dtemp1);
1522 *out_ <<
" - \\|W\\|_{\\infty} = " << maxNormInf (W) << endl
1523 <<
" - \\|X\\|_{\\infty} = " << maxNormInf (X) << endl;
1531template<
class ScalarType,
class MV>
1540 using MagnitudeType =
typename STS::magnitudeType;
1542 *out_ <<
" cgMethodWithInitGuess:" << endl;
1547 const ST one = STS::one();
1548 ST beta, betaOld = one, pAp, pApOld = one, alpha, rHz, rHzOld, rHzOld2 = one, lambdaMax;
1550 Teuchos::ArrayRCP<MagnitudeType> diag, offdiag;
1551 Teuchos::RCP<V> p, z, Ap;
1552 diag.resize(numIters);
1553 offdiag.resize(numIters-1);
1555 p = rcp(
new V(A.getRangeMap ()));
1556 z = rcp(
new V(A.getRangeMap ()));
1557 Ap = rcp(
new V(A.getRangeMap ()));
1560 solve (*p, D_inv, r);
1563 for (
int iter = 0; iter < numIters; ++iter) {
1565 *out_ <<
" Iteration " << iter << endl;
1570 r.update (-alpha, *Ap, one);
1572 solve (*z, D_inv, r);
1574 beta = rHz / rHzOld;
1575 p->update (one, *z, beta);
1577 diag[iter] = STS::real((betaOld*betaOld * pApOld + pAp) / rHzOld);
1578 offdiag[iter-1] = -STS::real((betaOld * pApOld / (sqrt(rHzOld * rHzOld2))));
1580 *out_ <<
" diag[" << iter <<
"] = " << diag[iter] << endl;
1581 *out_ <<
" offdiag["<< iter-1 <<
"] = " << offdiag[iter-1] << endl;
1582 *out_ <<
" rHz = "<<rHz <<endl;
1583 *out_ <<
" alpha = "<<alpha<<endl;
1584 *out_ <<
" beta = "<<beta<<endl;
1587 diag[iter] = STS::real(pAp/rHzOld);
1589 *out_ <<
" diag[" << iter <<
"] = " << diag[iter] << endl;
1590 *out_ <<
" rHz = "<<rHz <<endl;
1591 *out_ <<
" alpha = "<<alpha<<endl;
1592 *out_ <<
" beta = "<<beta<<endl;
1600 lambdaMax = LapackHelper<ST>::tri_diag_spectral_radius(diag, offdiag);
1606template<
class ScalarType,
class MV>
1609cgMethod (
const op_type& A,
const V& D_inv,
const int numIters)
1614 *out_ <<
"cgMethod:" << endl;
1618 if (eigVector_.is_null()) {
1619 r = rcp(
new V(A.getDomainMap ()));
1620 if (eigKeepVectors_)
1623 Details::computeInitialGuessForCG (D_inv,*r);
1627 ST lambdaMax = cgMethodWithInitGuess (A, D_inv, numIters, *r);
1632template<
class ScalarType,
class MV>
1633Teuchos::RCP<const typename Chebyshev<ScalarType, MV>::row_matrix_type>
1638template<
class ScalarType,
class MV>
1646template<
class ScalarType,
class MV>
1655 const size_t B_numVecs = B.getNumVectors ();
1656 if (W_.is_null () || W_->getNumVectors () != B_numVecs) {
1657 W_ = Teuchos::rcp (
new MV (B.getMap (), B_numVecs,
false));
1662template<
class ScalarType,
class MV>
1664Chebyshev<ScalarType, MV>::
1665makeSecondTempMultiVector (
const MV& B)
1671 const size_t B_numVecs = B.getNumVectors ();
1672 if (W2_.is_null () || W2_->getNumVectors () != B_numVecs) {
1673 W2_ = Teuchos::rcp (
new MV (B.getMap (), B_numVecs,
false));
1679template<
class ScalarType,
class MV>
1683 std::ostringstream oss;
1686 oss <<
"\"Ifpack2::Details::Chebyshev\":"
1688 <<
"degree: " << numIters_
1689 <<
", lambdaMax: " << lambdaMaxForApply_
1690 <<
", alpha: " << eigRatioForApply_
1691 <<
", lambdaMin: " << lambdaMinForApply_
1692 <<
", boost factor: " << boostFactor_
1693 <<
", algorithm: " << chebyshevAlgorithm_;
1694 if (!userInvDiag_.is_null())
1695 oss <<
", diagonal: user-supplied";
1700template<
class ScalarType,
class MV>
1703describe (Teuchos::FancyOStream& out,
1704 const Teuchos::EVerbosityLevel verbLevel)
const
1706 using Teuchos::TypeNameTraits;
1709 const Teuchos::EVerbosityLevel vl =
1710 (verbLevel == Teuchos::VERB_DEFAULT) ? Teuchos::VERB_LOW : verbLevel;
1711 if (vl == Teuchos::VERB_NONE) {
1721 Teuchos::OSTab tab0 (out);
1727 if (A_.is_null () || A_->getComm ().is_null ()) {
1731 myRank = A_->getComm ()->getRank ();
1736 out <<
"\"Ifpack2::Details::Chebyshev\":" << endl;
1738 Teuchos::OSTab tab1 (out);
1740 if (vl == Teuchos::VERB_LOW) {
1742 out <<
"degree: " << numIters_ << endl
1743 <<
"lambdaMax: " << lambdaMaxForApply_ << endl
1744 <<
"alpha: " << eigRatioForApply_ << endl
1745 <<
"lambdaMin: " << lambdaMinForApply_ << endl
1746 <<
"boost factor: " << boostFactor_ << endl;
1754 out <<
"Template parameters:" << endl;
1756 Teuchos::OSTab tab2 (out);
1757 out <<
"ScalarType: " << TypeNameTraits<ScalarType>::name () << endl
1758 <<
"MV: " << TypeNameTraits<MV>::name () << endl;
1764 out <<
"Computed parameters:" << endl;
1770 Teuchos::OSTab tab2 (out);
1776 if (D_.is_null ()) {
1778 out <<
"unset" << endl;
1781 else if (vl <= Teuchos::VERB_HIGH) {
1783 out <<
"set" << endl;
1792 D_->describe (out, vl);
1797 out <<
"W_: " << (W_.is_null () ?
"unset" :
"set") << endl
1798 <<
"computedLambdaMax_: " << computedLambdaMax_ << endl
1799 <<
"computedLambdaMin_: " << computedLambdaMin_ << endl
1800 <<
"lambdaMaxForApply_: " << lambdaMaxForApply_ << endl
1801 <<
"lambdaMinForApply_: " << lambdaMinForApply_ << endl
1802 <<
"eigRatioForApply_: " << eigRatioForApply_ << endl;
1807 out <<
"User parameters:" << endl;
1812 Teuchos::OSTab tab2 (out);
1813 out <<
"userInvDiag_: ";
1814 if (userInvDiag_.is_null ()) {
1815 out <<
"unset" << endl;
1817 else if (vl <= Teuchos::VERB_HIGH) {
1818 out <<
"set" << endl;
1824 userInvDiag_->describe (out, vl);
1827 out <<
"userLambdaMax_: " << userLambdaMax_ << endl
1828 <<
"userLambdaMin_: " << userLambdaMin_ << endl
1829 <<
"userEigRatio_: " << userEigRatio_ << endl
1830 <<
"numIters_: " << numIters_ << endl
1831 <<
"eigMaxIters_: " << eigMaxIters_ << endl
1832 <<
"eigRelTolerance_: " << eigRelTolerance_ << endl
1833 <<
"eigNormalizationFreq_: " << eigNormalizationFreq_ << endl
1834 <<
"zeroStartingSolution_: " << zeroStartingSolution_ << endl
1835 <<
"assumeMatrixUnchanged_: " << assumeMatrixUnchanged_ << endl
1836 <<
"chebyshevAlgorithm_: " << chebyshevAlgorithm_ << endl
1837 <<
"computeMaxResNorm_: " << computeMaxResNorm_ << endl;