358 using Teuchos::rcp_const_cast;
370 const ST defaultLambdaMax = STS::nan ();
371 const ST defaultLambdaMin = STS::nan ();
378 const ST defaultEigRatio = Teuchos::as<ST> (30);
379 const MT defaultBoostFactor =
static_cast<MT> (1.1);
380 const ST defaultMinDiagVal = STS::eps ();
381 const int defaultNumIters = 1;
382 const int defaultEigMaxIters = 10;
383 const MT defaultEigRelTolerance = Teuchos::ScalarTraits<MT>::zero ();
384 const bool defaultEigKeepVectors =
false;
385 const int defaultEigNormalizationFreq = 1;
386 const bool defaultZeroStartingSolution =
true;
387 const bool defaultAssumeMatrixUnchanged =
false;
388 const std::string defaultChebyshevAlgorithm =
"first";
389 const bool defaultComputeMaxResNorm =
false;
390 const bool defaultComputeSpectralRadius =
true;
391 const bool defaultCkUseNativeSpMV =
false;
392 const bool defaultDebug =
false;
398 RCP<const V> userInvDiagCopy;
399 ST lambdaMax = defaultLambdaMax;
400 ST lambdaMin = defaultLambdaMin;
401 ST eigRatio = defaultEigRatio;
402 MT boostFactor = defaultBoostFactor;
403 ST minDiagVal = defaultMinDiagVal;
404 int numIters = defaultNumIters;
405 int eigMaxIters = defaultEigMaxIters;
406 MT eigRelTolerance = defaultEigRelTolerance;
407 bool eigKeepVectors = defaultEigKeepVectors;
408 int eigNormalizationFreq = defaultEigNormalizationFreq;
409 bool zeroStartingSolution = defaultZeroStartingSolution;
410 bool assumeMatrixUnchanged = defaultAssumeMatrixUnchanged;
411 std::string chebyshevAlgorithm = defaultChebyshevAlgorithm;
412 bool computeMaxResNorm = defaultComputeMaxResNorm;
413 bool computeSpectralRadius = defaultComputeSpectralRadius;
414 bool ckUseNativeSpMV = defaultCkUseNativeSpMV;
415 bool debug = defaultDebug;
422 if (plist.isType<
bool> (
"debug")) {
423 debug = plist.get<
bool> (
"debug");
425 else if (plist.isType<
int> (
"debug")) {
426 const int debugInt = plist.get<
bool> (
"debug");
427 debug = debugInt != 0;
440 const char opInvDiagLabel[] =
"chebyshev: operator inv diagonal";
441 if (plist.isParameter (opInvDiagLabel)) {
443 RCP<const V> userInvDiag;
445 if (plist.isType<
const V*> (opInvDiagLabel)) {
446 const V* rawUserInvDiag =
447 plist.get<
const V*> (opInvDiagLabel);
449 userInvDiag = rcp (rawUserInvDiag,
false);
451 else if (plist.isType<
const V*> (opInvDiagLabel)) {
452 V* rawUserInvDiag = plist.get<
V*> (opInvDiagLabel);
454 userInvDiag = rcp (
const_cast<const V*
> (rawUserInvDiag),
false);
456 else if (plist.isType<RCP<const V>> (opInvDiagLabel)) {
457 userInvDiag = plist.get<RCP<const V> > (opInvDiagLabel);
459 else if (plist.isType<RCP<V>> (opInvDiagLabel)) {
460 RCP<V> userInvDiagNonConst =
461 plist.get<RCP<V> > (opInvDiagLabel);
462 userInvDiag = rcp_const_cast<const V> (userInvDiagNonConst);
464 else if (plist.isType<
const V> (opInvDiagLabel)) {
465 const V& userInvDiagRef = plist.get<
const V> (opInvDiagLabel);
466 userInvDiagCopy = rcp (
new V (userInvDiagRef, Teuchos::Copy));
467 userInvDiag = userInvDiagCopy;
469 else if (plist.isType<
V> (opInvDiagLabel)) {
470 V& userInvDiagNonConstRef = plist.get<
V> (opInvDiagLabel);
471 const V& userInvDiagRef =
const_cast<const V&
> (userInvDiagNonConstRef);
472 userInvDiagCopy = rcp (
new V (userInvDiagRef, Teuchos::Copy));
473 userInvDiag = userInvDiagCopy;
483 if (! userInvDiag.is_null () && userInvDiagCopy.is_null ()) {
484 userInvDiagCopy = rcp (
new V (*userInvDiag, Teuchos::Copy));
494 if (plist.isParameter (
"chebyshev: use native spmv"))
495 ckUseNativeSpMV = plist.get(
"chebyshev: use native spmv", ckUseNativeSpMV);
500 if (plist.isParameter (
"chebyshev: max eigenvalue")) {
501 if (plist.isType<
double>(
"chebyshev: max eigenvalue"))
502 lambdaMax = plist.get<
double> (
"chebyshev: max eigenvalue");
504 lambdaMax = plist.get<
ST> (
"chebyshev: max eigenvalue");
505 TEUCHOS_TEST_FOR_EXCEPTION(
506 STS::isnaninf (lambdaMax), std::invalid_argument,
507 "Ifpack2::Chebyshev::setParameters: \"chebyshev: max eigenvalue\" "
508 "parameter is NaN or Inf. This parameter is optional, but if you "
509 "choose to supply it, it must have a finite value.");
511 if (plist.isParameter (
"chebyshev: min eigenvalue")) {
512 if (plist.isType<
double>(
"chebyshev: min eigenvalue"))
513 lambdaMin = plist.get<
double> (
"chebyshev: min eigenvalue");
515 lambdaMin = plist.get<
ST> (
"chebyshev: min eigenvalue");
516 TEUCHOS_TEST_FOR_EXCEPTION(
517 STS::isnaninf (lambdaMin), std::invalid_argument,
518 "Ifpack2::Chebyshev::setParameters: \"chebyshev: min eigenvalue\" "
519 "parameter is NaN or Inf. This parameter is optional, but if you "
520 "choose to supply it, it must have a finite value.");
524 if (plist.isParameter (
"smoother: Chebyshev alpha")) {
525 if (plist.isType<
double>(
"smoother: Chebyshev alpha"))
526 eigRatio = plist.get<
double> (
"smoother: Chebyshev alpha");
528 eigRatio = plist.get<
ST> (
"smoother: Chebyshev alpha");
531 eigRatio = plist.get (
"chebyshev: ratio eigenvalue", eigRatio);
532 TEUCHOS_TEST_FOR_EXCEPTION(
533 STS::isnaninf (eigRatio), std::invalid_argument,
534 "Ifpack2::Chebyshev::setParameters: \"chebyshev: ratio eigenvalue\" "
535 "parameter (also called \"smoother: Chebyshev alpha\") is NaN or Inf. "
536 "This parameter is optional, but if you choose to supply it, it must have "
543 TEUCHOS_TEST_FOR_EXCEPTION(
544 STS::real (eigRatio) < STS::real (STS::one ()),
545 std::invalid_argument,
546 "Ifpack2::Chebyshev::setParameters: \"chebyshev: ratio eigenvalue\""
547 "parameter (also called \"smoother: Chebyshev alpha\") must be >= 1, "
548 "but you supplied the value " << eigRatio <<
".");
553 const char paramName[] =
"chebyshev: boost factor";
555 if (plist.isParameter (paramName)) {
556 if (plist.isType<
MT> (paramName)) {
557 boostFactor = plist.get<
MT> (paramName);
559 else if (! std::is_same<double, MT>::value &&
560 plist.isType<
double> (paramName)) {
561 const double dblBF = plist.get<
double> (paramName);
562 boostFactor =
static_cast<MT> (dblBF);
565 TEUCHOS_TEST_FOR_EXCEPTION
566 (
true, std::invalid_argument,
567 "Ifpack2::Chebyshev::setParameters: \"chebyshev: boost factor\""
568 "parameter must have type magnitude_type (MT) or double.");
578 plist.set (paramName, defaultBoostFactor);
580 TEUCHOS_TEST_FOR_EXCEPTION
581 (boostFactor < Teuchos::ScalarTraits<MT>::one (), std::invalid_argument,
582 "Ifpack2::Chebyshev::setParameters: \"" << paramName <<
"\" parameter "
583 "must be >= 1, but you supplied the value " << boostFactor <<
".");
587 minDiagVal = plist.get (
"chebyshev: min diagonal value", minDiagVal);
588 TEUCHOS_TEST_FOR_EXCEPTION(
589 STS::isnaninf (minDiagVal), std::invalid_argument,
590 "Ifpack2::Chebyshev::setParameters: \"chebyshev: min diagonal value\" "
591 "parameter is NaN or Inf. This parameter is optional, but if you choose "
592 "to supply it, it must have a finite value.");
595 if (plist.isParameter (
"smoother: sweeps")) {
596 numIters = plist.get<
int> (
"smoother: sweeps");
598 if (plist.isParameter (
"relaxation: sweeps")) {
599 numIters = plist.get<
int> (
"relaxation: sweeps");
601 numIters = plist.get (
"chebyshev: degree", numIters);
602 TEUCHOS_TEST_FOR_EXCEPTION(
603 numIters < 0, std::invalid_argument,
604 "Ifpack2::Chebyshev::setParameters: \"chebyshev: degree\" parameter (also "
605 "called \"smoother: sweeps\" or \"relaxation: sweeps\") must be a "
606 "nonnegative integer. You gave a value of " << numIters <<
".");
609 if (plist.isParameter (
"eigen-analysis: iterations")) {
610 eigMaxIters = plist.get<
int> (
"eigen-analysis: iterations");
612 eigMaxIters = plist.get (
"chebyshev: eigenvalue max iterations", eigMaxIters);
613 TEUCHOS_TEST_FOR_EXCEPTION(
614 eigMaxIters < 0, std::invalid_argument,
615 "Ifpack2::Chebyshev::setParameters: \"chebyshev: eigenvalue max iterations"
616 "\" parameter (also called \"eigen-analysis: iterations\") must be a "
617 "nonnegative integer. You gave a value of " << eigMaxIters <<
".");
619 if (plist.isType<
double>(
"chebyshev: eigenvalue relative tolerance"))
620 eigRelTolerance = Teuchos::as<MT>(plist.get<
double> (
"chebyshev: eigenvalue relative tolerance"));
621 else if (plist.isType<
MT>(
"chebyshev: eigenvalue relative tolerance"))
622 eigRelTolerance = plist.get<
MT> (
"chebyshev: eigenvalue relative tolerance");
623 else if (plist.isType<
ST>(
"chebyshev: eigenvalue relative tolerance"))
624 eigRelTolerance = Teuchos::ScalarTraits<ST>::magnitude(plist.get<
ST> (
"chebyshev: eigenvalue relative tolerance"));
626 eigKeepVectors = plist.get (
"chebyshev: eigenvalue keep vectors", eigKeepVectors);
628 eigNormalizationFreq = plist.get (
"chebyshev: eigenvalue normalization frequency", eigNormalizationFreq);
629 TEUCHOS_TEST_FOR_EXCEPTION(
630 eigNormalizationFreq < 0, std::invalid_argument,
631 "Ifpack2::Chebyshev::setParameters: \"chebyshev: eigenvalue normalization frequency"
632 "\" parameter must be a "
633 "nonnegative integer. You gave a value of " << eigNormalizationFreq <<
".")
635 zeroStartingSolution = plist.get (
"chebyshev: zero starting solution",
636 zeroStartingSolution);
637 assumeMatrixUnchanged = plist.get (
"chebyshev: assume matrix does not change",
638 assumeMatrixUnchanged);
642 if (plist.isParameter (
"chebyshev: algorithm")) {
643 chebyshevAlgorithm = plist.get<std::string> (
"chebyshev: algorithm");
644 TEUCHOS_TEST_FOR_EXCEPTION(
645 chebyshevAlgorithm !=
"first" &&
646 chebyshevAlgorithm !=
"textbook" &&
647 chebyshevAlgorithm !=
"fourth" &&
648 chebyshevAlgorithm !=
"opt_fourth",
649 std::invalid_argument,
650 "Ifpack2::Chebyshev: Ifpack2 only supports \"first\", \"textbook\", \"fourth\", and \"opt_fourth\", for \"chebyshev: algorithm\".");
653#ifdef IFPACK2_ENABLE_DEPRECATED_CODE
656 if (!plist.isParameter (
"chebyshev: algorithm")) {
657 if (plist.isParameter (
"chebyshev: textbook algorithm")) {
658 const bool textbookAlgorithm = plist.get<
bool> (
"chebyshev: textbook algorithm");
659 if(textbookAlgorithm){
660 chebyshevAlgorithm =
"textbook";
662 chebyshevAlgorithm =
"first";
668 if (plist.isParameter (
"chebyshev: compute max residual norm")) {
669 computeMaxResNorm = plist.get<
bool> (
"chebyshev: compute max residual norm");
671 if (plist.isParameter (
"chebyshev: compute spectral radius")) {
672 computeSpectralRadius = plist.get<
bool> (
"chebyshev: compute spectral radius");
680 TEUCHOS_TEST_FOR_EXCEPTION
681 (plist.isType<
bool> (
"chebyshev: use block mode") &&
682 ! plist.get<
bool> (
"chebyshev: use block mode"),
683 std::invalid_argument,
684 "Ifpack2::Chebyshev requires that if you set \"chebyshev: use "
685 "block mode\" at all, you must set it to false. "
686 "Ifpack2::Chebyshev does not implement Ifpack's block mode.");
687 TEUCHOS_TEST_FOR_EXCEPTION
688 (plist.isType<
bool> (
"chebyshev: solve normal equations") &&
689 ! plist.get<
bool> (
"chebyshev: solve normal equations"),
690 std::invalid_argument,
691 "Ifpack2::Chebyshev does not and will never implement the Ifpack "
692 "parameter \"chebyshev: solve normal equations\". If you want to "
693 "solve the normal equations, construct a Tpetra::Operator that "
694 "implements A^* A, and use Chebyshev to solve A^* A x = A^* b.");
702 std::string eigenAnalysisType (
"power-method");
703 if (plist.isParameter (
"eigen-analysis: type")) {
704 eigenAnalysisType = plist.get<std::string> (
"eigen-analysis: type");
705 TEUCHOS_TEST_FOR_EXCEPTION(
706 eigenAnalysisType !=
"power-method" &&
707 eigenAnalysisType !=
"power method" &&
708 eigenAnalysisType !=
"cg",
709 std::invalid_argument,
710 "Ifpack2::Chebyshev: Ifpack2 only supports \"power method\" and \"cg\" for \"eigen-analysis: type\".");
714 userInvDiag_ = userInvDiagCopy;
715 userLambdaMax_ = lambdaMax;
716 userLambdaMin_ = lambdaMin;
717 userEigRatio_ = eigRatio;
718 boostFactor_ =
static_cast<MT> (boostFactor);
719 minDiagVal_ = minDiagVal;
720 numIters_ = numIters;
721 eigMaxIters_ = eigMaxIters;
722 eigRelTolerance_ = eigRelTolerance;
723 eigKeepVectors_ = eigKeepVectors;
724 eigNormalizationFreq_ = eigNormalizationFreq;
725 eigenAnalysisType_ = eigenAnalysisType;
726 zeroStartingSolution_ = zeroStartingSolution;
727 assumeMatrixUnchanged_ = assumeMatrixUnchanged;
728 chebyshevAlgorithm_ = chebyshevAlgorithm;
729 computeMaxResNorm_ = computeMaxResNorm;
730 computeSpectralRadius_ = computeSpectralRadius;
731 ckUseNativeSpMV_ = ckUseNativeSpMV;
737 if (A_.is_null () || A_->getComm ().is_null ()) {
743 myRank = A_->getComm ()->getRank ();
747 out_ = Teuchos::getFancyOStream (Teuchos::rcpFromRef (std::cerr));
750 using Teuchos::oblackholestream;
751 RCP<oblackholestream> blackHole (
new oblackholestream ());
752 out_ = Teuchos::getFancyOStream (blackHole);
757 out_ = Teuchos::null;
762template<
class ScalarType,
class MV>
764Chebyshev<ScalarType, MV>::reset ()
768 diagOffsets_ = offsets_type ();
769 savedDiagOffsets_ =
false;
771 computedLambdaMax_ = STS::nan ();
772 computedLambdaMin_ = STS::nan ();
773 eigVector_ = Teuchos::null;
774 eigVector2_ = Teuchos::null;
778template<
class ScalarType,
class MV>
781setMatrix (
const Teuchos::RCP<const row_matrix_type>& A)
783 if (A.getRawPtr () != A_.getRawPtr ()) {
784 if (! assumeMatrixUnchanged_) {
796 if (A.is_null () || A->getComm ().is_null ()) {
802 myRank = A->getComm ()->getRank ();
806 out_ = Teuchos::getFancyOStream (Teuchos::rcpFromRef (std::cerr));
809 Teuchos::RCP<Teuchos::oblackholestream> blackHole (
new Teuchos::oblackholestream ());
810 out_ = Teuchos::getFancyOStream (blackHole);
815 out_ = Teuchos::null;
820template<
class ScalarType,
class MV>
829 typedef Tpetra::CrsMatrix<
typename MV::scalar_type,
830 typename MV::local_ordinal_type,
831 typename MV::global_ordinal_type,
832 typename MV::node_type> crs_matrix_type;
834 TEUCHOS_TEST_FOR_EXCEPTION(
835 A_.is_null (), std::runtime_error,
"Ifpack2::Chebyshev::compute: The input "
836 "matrix A is null. Please call setMatrix() with a nonnull input matrix "
837 "before calling this method.");
852 if (userInvDiag_.is_null ()) {
853 Teuchos::RCP<const crs_matrix_type> A_crsMat =
854 Teuchos::rcp_dynamic_cast<const crs_matrix_type> (A_);
857 if (! A_crsMat.is_null () && A_crsMat->isFillComplete ()) {
859 const size_t lclNumRows = A_crsMat->getLocalNumRows ();
860 if (diagOffsets_.extent (0) < lclNumRows) {
861 diagOffsets_ = offsets_type ();
862 diagOffsets_ = offsets_type (
"offsets", lclNumRows);
864 A_crsMat->getCrsGraph ()->getLocalDiagOffsets (diagOffsets_);
865 savedDiagOffsets_ =
true;
866 D_ = makeInverseDiagonal (*A_,
true);
869 D_ = makeInverseDiagonal (*A_);
872 else if (! assumeMatrixUnchanged_) {
873 if (! A_crsMat.is_null () && A_crsMat->isFillComplete ()) {
876 if (! savedDiagOffsets_) {
877 const size_t lclNumRows = A_crsMat->getLocalNumRows ();
878 if (diagOffsets_.extent (0) < lclNumRows) {
879 diagOffsets_ = offsets_type ();
880 diagOffsets_ = offsets_type (
"offsets", lclNumRows);
882 A_crsMat->getCrsGraph ()->getLocalDiagOffsets (diagOffsets_);
883 savedDiagOffsets_ =
true;
886 D_ = makeInverseDiagonal (*A_,
true);
889 D_ = makeInverseDiagonal (*A_);
894 D_ = makeRangeMapVectorConst (userInvDiag_);
898 const bool computedEigenvalueEstimates =
899 STS::isnaninf (computedLambdaMax_) || STS::isnaninf (computedLambdaMin_);
909 if (! assumeMatrixUnchanged_ ||
910 (! computedEigenvalueEstimates && STS::isnaninf (userLambdaMax_))) {
911 ST computedLambdaMax;
912 if ((eigenAnalysisType_ ==
"power method") || (eigenAnalysisType_ ==
"power-method")) {
914 if (eigVector_.is_null()) {
915 x = Teuchos::rcp(
new V(A_->getDomainMap ()));
923 if (eigVector2_.is_null()) {
924 y = rcp(
new V(A_->getRangeMap ()));
930 Teuchos::RCP<Teuchos::FancyOStream> stream = (debug_ ? out_ : Teuchos::null);
932 eigRelTolerance_, eigNormalizationFreq_, stream,
933 computeSpectralRadius_);
936 computedLambdaMax = cgMethod (*A_, *D_, eigMaxIters_);
937 TEUCHOS_TEST_FOR_EXCEPTION(
938 STS::isnaninf (computedLambdaMax),
940 "Ifpack2::Chebyshev::compute: Estimation of the max eigenvalue "
941 "of D^{-1} A failed, by producing Inf or NaN. This probably means that "
942 "the matrix contains Inf or NaN values, or that it is badly scaled.");
943 TEUCHOS_TEST_FOR_EXCEPTION(
944 STS::isnaninf (userEigRatio_),
946 "Ifpack2::Chebyshev::compute: userEigRatio_ is Inf or NaN."
947 << endl <<
"This should be impossible." << endl <<
948 "Please report this bug to the Ifpack2 developers.");
954 const ST computedLambdaMin = computedLambdaMax / userEigRatio_;
957 computedLambdaMax_ = computedLambdaMax;
958 computedLambdaMin_ = computedLambdaMin;
960 TEUCHOS_TEST_FOR_EXCEPTION(
961 STS::isnaninf (userLambdaMax_) && STS::isnaninf (computedLambdaMax_),
963 "Ifpack2::Chebyshev::compute: " << endl <<
964 "Both userLambdaMax_ and computedLambdaMax_ are Inf or NaN."
965 << endl <<
"This should be impossible." << endl <<
966 "Please report this bug to the Ifpack2 developers.");
974 lambdaMaxForApply_ = STS::isnaninf (userLambdaMax_) ? computedLambdaMax_ : userLambdaMax_;
987 lambdaMinForApply_ = lambdaMaxForApply_ / userEigRatio_;
988 eigRatioForApply_ = userEigRatio_;
990 if (chebyshevAlgorithm_ ==
"first") {
993 const ST one = Teuchos::as<ST> (1);
996 if (STS::magnitude (lambdaMaxForApply_ - one) < Teuchos::as<MT> (1.0e-6)) {
997 lambdaMinForApply_ = one;
998 lambdaMaxForApply_ = lambdaMinForApply_;
999 eigRatioForApply_ = one;
1005template<
class ScalarType,
class MV>
1009 return lambdaMaxForApply_;
1013template<
class ScalarType,
class MV>
1017 const char prefix[] =
"Ifpack2::Chebyshev::apply: ";
1020 *out_ <<
"apply: " << std::endl;
1022 TEUCHOS_TEST_FOR_EXCEPTION
1023 (A_.is_null (), std::runtime_error, prefix <<
"The input matrix A is null. "
1024 " Please call setMatrix() with a nonnull input matrix, and then call "
1025 "compute(), before calling this method.");
1026 TEUCHOS_TEST_FOR_EXCEPTION
1027 (STS::isnaninf (lambdaMaxForApply_), std::runtime_error,
1028 prefix <<
"There is no estimate for the max eigenvalue."
1029 << std::endl << computeBeforeApplyReminder);
1030 TEUCHOS_TEST_FOR_EXCEPTION
1031 (STS::isnaninf (lambdaMinForApply_), std::runtime_error,
1032 prefix <<
"There is no estimate for the min eigenvalue."
1033 << std::endl << computeBeforeApplyReminder);
1034 TEUCHOS_TEST_FOR_EXCEPTION
1035 (STS::isnaninf (eigRatioForApply_), std::runtime_error,
1036 prefix <<
"There is no estimate for the ratio of the max "
1037 "eigenvalue to the min eigenvalue."
1038 << std::endl << computeBeforeApplyReminder);
1039 TEUCHOS_TEST_FOR_EXCEPTION
1040 (D_.is_null (), std::runtime_error, prefix <<
"The vector of inverse "
1041 "diagonal entries of the matrix has not yet been computed."
1042 << std::endl << computeBeforeApplyReminder);
1044 if (chebyshevAlgorithm_ ==
"fourth" || chebyshevAlgorithm_ ==
"opt_fourth") {
1045 fourthKindApplyImpl (*A_, B, X, numIters_, lambdaMaxForApply_, *D_);
1047 else if (chebyshevAlgorithm_ ==
"textbook") {
1048 textbookApplyImpl (*A_, B, X, numIters_, lambdaMaxForApply_,
1049 lambdaMinForApply_, eigRatioForApply_, *D_);
1052 ifpackApplyImpl (*A_, B, X, numIters_, lambdaMaxForApply_,
1053 lambdaMinForApply_, eigRatioForApply_, *D_);
1056 if (computeMaxResNorm_ && B.getNumVectors () > 0) {
1057 MV R (B.getMap (), B.getNumVectors ());
1058 computeResidual (R, B, *A_, X);
1059 Teuchos::Array<MT> norms (B.getNumVectors ());
1061 return *std::max_element (norms.begin (), norms.end ());
1064 return Teuchos::ScalarTraits<MT>::zero ();
1068template<
class ScalarType,
class MV>
1071print (std::ostream& out)
1073 using Teuchos::rcpFromRef;
1074 this->
describe (* (Teuchos::getFancyOStream (rcpFromRef (out))),
1075 Teuchos::VERB_MEDIUM);
1078template<
class ScalarType,
class MV>
1082 const ScalarType& alpha,
1087 solve (W, alpha, D_inv, B);
1088 Tpetra::deep_copy (X, W);
1091template<
class ScalarType,
class MV>
1095 const Teuchos::ETransp mode)
1097 Tpetra::Details::residual(A,X,B,R);
1100template <
class ScalarType,
class MV>
1102Chebyshev<ScalarType, MV>::
1103solve (MV& Z,
const V& D_inv,
const MV& R) {
1104 Z.elementWiseMultiply (STS::one(), D_inv, R, STS::zero());
1107template<
class ScalarType,
class MV>
1110solve (MV& Z,
const ST alpha,
const V& D_inv,
const MV& R) {
1111 Z.elementWiseMultiply (alpha, D_inv, R, STS::zero());
1114template<
class ScalarType,
class MV>
1115Teuchos::RCP<const typename Chebyshev<ScalarType, MV>::V>
1120 using Teuchos::rcpFromRef;
1121 using Teuchos::rcp_dynamic_cast;
1124 if (!D_.is_null() &&
1125 D_->getMap()->isSameAs(*(A.getRowMap ()))) {
1127 *out_ <<
"Reusing pre-existing vector for diagonal extraction" << std::endl;
1128 D_rowMap = Teuchos::rcp_const_cast<V>(D_);
1130 D_rowMap = Teuchos::rcp(
new V (A.getRowMap (),
false));
1132 *out_ <<
"Allocated new vector for diagonal extraction" << std::endl;
1134 if (useDiagOffsets) {
1138 typedef Tpetra::CrsMatrix<
typename MV::scalar_type,
1139 typename MV::local_ordinal_type,
1140 typename MV::global_ordinal_type,
1141 typename MV::node_type> crs_matrix_type;
1142 RCP<const crs_matrix_type> A_crsMat =
1143 rcp_dynamic_cast<const crs_matrix_type> (rcpFromRef (A));
1144 if (! A_crsMat.is_null ()) {
1145 TEUCHOS_TEST_FOR_EXCEPTION(
1146 ! savedDiagOffsets_, std::logic_error,
1147 "Ifpack2::Details::Chebyshev::makeInverseDiagonal: "
1148 "It is not allowed to call this method with useDiagOffsets=true, "
1149 "if you have not previously saved offsets of diagonal entries. "
1150 "This situation should never arise if this class is used properly. "
1151 "Please report this bug to the Ifpack2 developers.");
1152 A_crsMat->getLocalDiagCopy (*D_rowMap, diagOffsets_);
1158 A.getLocalDiagCopy (*D_rowMap);
1160 RCP<V> D_rangeMap = makeRangeMapVector (D_rowMap);
1166 bool foundNonpositiveValue =
false;
1168 auto D_lcl = D_rangeMap->getLocalViewHost (Tpetra::Access::ReadOnly);
1169 auto D_lcl_1d = Kokkos::subview (D_lcl, Kokkos::ALL (), 0);
1171 typedef typename MV::impl_scalar_type IST;
1172 typedef typename MV::local_ordinal_type LO;
1173 typedef Kokkos::ArithTraits<IST> ATS;
1174 typedef Kokkos::ArithTraits<typename ATS::mag_type> STM;
1176 const LO lclNumRows =
static_cast<LO
> (D_rangeMap->getLocalLength ());
1177 for (LO i = 0; i < lclNumRows; ++i) {
1178 if (STS::real (D_lcl_1d(i)) <= STM::zero ()) {
1179 foundNonpositiveValue =
true;
1185 using Teuchos::outArg;
1186 using Teuchos::REDUCE_MIN;
1187 using Teuchos::reduceAll;
1189 const int lclSuccess = foundNonpositiveValue ? 0 : 1;
1190 int gblSuccess = lclSuccess;
1191 if (! D_rangeMap->getMap ().is_null () && D_rangeMap->getMap ()->getComm ().is_null ()) {
1192 const Teuchos::Comm<int>& comm = * (D_rangeMap->getMap ()->getComm ());
1193 reduceAll<int, int> (comm, REDUCE_MIN, lclSuccess, outArg (gblSuccess));
1195 if (gblSuccess == 1) {
1196 *out_ <<
"makeInverseDiagonal: The matrix's diagonal entries all have "
1197 "positive real part (this is good for Chebyshev)." << std::endl;
1200 *out_ <<
"makeInverseDiagonal: The matrix's diagonal has at least one "
1201 "entry with nonpositive real part, on at least one process in the "
1202 "matrix's communicator. This is bad for Chebyshev." << std::endl;
1208 reciprocal_threshold (*D_rangeMap, minDiagVal_);
1209 return Teuchos::rcp_const_cast<const V> (D_rangeMap);
1213template<
class ScalarType,
class MV>
1214Teuchos::RCP<const typename Chebyshev<ScalarType, MV>::V>
1220 typedef Tpetra::Export<
typename MV::local_ordinal_type,
1221 typename MV::global_ordinal_type,
1222 typename MV::node_type> export_type;
1226 TEUCHOS_TEST_FOR_EXCEPTION(
1227 A_.is_null (), std::logic_error,
"Ifpack2::Details::Chebyshev::"
1228 "makeRangeMapVector: The input matrix A is null. Please call setMatrix() "
1229 "with a nonnull input matrix before calling this method. This is probably "
1230 "a bug in Ifpack2; please report this bug to the Ifpack2 developers.");
1231 TEUCHOS_TEST_FOR_EXCEPTION(
1232 D.is_null (), std::logic_error,
"Ifpack2::Details::Chebyshev::"
1233 "makeRangeMapVector: The input Vector D is null. This is probably "
1234 "a bug in Ifpack2; please report this bug to the Ifpack2 developers.");
1236 RCP<const map_type> sourceMap = D->getMap ();
1237 RCP<const map_type> rangeMap = A_->getRangeMap ();
1238 RCP<const map_type> rowMap = A_->getRowMap ();
1240 if (rangeMap->isSameAs (*sourceMap)) {
1246 RCP<const export_type> exporter;
1250 if (sourceMap->isSameAs (*rowMap)) {
1252 exporter = A_->getGraph ()->getExporter ();
1255 exporter = rcp (
new export_type (sourceMap, rangeMap));
1258 if (exporter.is_null ()) {
1262 RCP<V> D_out = rcp (
new V (*D, Teuchos::Copy));
1263 D_out->doExport (*D, *exporter, Tpetra::ADD);
1264 return Teuchos::rcp_const_cast<const V> (D_out);
1270template<
class ScalarType,
class MV>
1271Teuchos::RCP<typename Chebyshev<ScalarType, MV>::V>
1275 using Teuchos::rcp_const_cast;
1276 return rcp_const_cast<V> (makeRangeMapVectorConst (rcp_const_cast<V> (D)));
1280template<
class ScalarType,
class MV>
1290 const V& D_inv)
const
1293 const ST myLambdaMin = lambdaMax / eigRatio;
1295 const ST zero = Teuchos::as<ST> (0);
1296 const ST one = Teuchos::as<ST> (1);
1297 const ST two = Teuchos::as<ST> (2);
1298 const ST d = (lambdaMax + myLambdaMin) / two;
1299 const ST c = (lambdaMax - myLambdaMin) / two;
1301 if (zeroStartingSolution_ && numIters > 0) {
1305 MV R (B.getMap (), B.getNumVectors (),
false);
1306 MV P (B.getMap (), B.getNumVectors (),
false);
1307 MV Z (B.getMap (), B.getNumVectors (),
false);
1309 for (
int i = 0; i < numIters; ++i) {
1310 computeResidual (R, B, A, X);
1311 solve (Z, D_inv, R);
1319 beta = alpha * (c/two) * (c/two);
1320 alpha = one / (d - beta);
1321 P.update (one, Z, beta);
1323 X.update (alpha, P, one);
1330template<
class ScalarType,
class MV>
1341 std::vector<ScalarType> betas(numIters, 1.0);
1342 if(chebyshevAlgorithm_ ==
"opt_fourth"){
1346 const ST invEig = MT(1) / (lambdaMax * boostFactor_);
1349 Teuchos::RCP<MV> Z_ptr = makeTempMultiVector (B);
1354 Teuchos::RCP<MV> X4_ptr = makeSecondTempMultiVector (B);
1358 if (! zeroStartingSolution_) {
1361 Tpetra::deep_copy (X4, X);
1363 if (ck_.is_null ()) {
1364 Teuchos::RCP<const op_type> A_op = A_;
1369 ck_->compute (Z, MT(4.0/3.0) * invEig,
const_cast<V&
> (D_inv),
1370 const_cast<MV&
> (B), X4, STS::zero());
1373 X.update (betas[0], Z, STS::one());
1377 firstIterationWithZeroStartingSolution (Z, MT(4.0/3.0) * invEig, D_inv, B, X4);
1380 X.update (betas[0], Z, STS::zero());
1383 if (numIters > 1 && ck_.is_null ()) {
1384 Teuchos::RCP<const op_type> A_op = A_;
1388 for (
int i = 1; i < numIters; ++i) {
1389 const ST zScale = (2.0 * i - 1.0) / (2.0 * i + 3.0);
1390 const ST rScale = MT((8.0 * i + 4.0) / (2.0 * i + 3.0)) * invEig;
1394 ck_->compute (Z, rScale,
const_cast<V&
> (D_inv),
1395 const_cast<MV&
> (B), (X4), zScale);
1398 X.update (betas[i], Z, STS::one());
1402template<
class ScalarType,
class MV>
1404Chebyshev<ScalarType, MV>::maxNormInf (
const MV& X) {
1405 Teuchos::Array<MT> norms (X.getNumVectors ());
1406 X.normInf (norms());
1407 return *std::max_element (norms.begin (), norms.end ());
1410template<
class ScalarType,
class MV>
1423#ifdef HAVE_IFPACK2_DEBUG
1424 const bool debug = debug_;
1426 const bool debug =
false;
1430 *out_ <<
" \\|B\\|_{\\infty} = " << maxNormInf (B) << endl;
1431 *out_ <<
" \\|X\\|_{\\infty} = " << maxNormInf (X) << endl;
1434 if (numIters <= 0) {
1437 const ST zero =
static_cast<ST
> (0.0);
1438 const ST one =
static_cast<ST
> (1.0);
1439 const ST two =
static_cast<ST
> (2.0);
1442 if (lambdaMin == one && lambdaMax == lambdaMin) {
1443 solve (X, D_inv, B);
1448 const ST alpha = lambdaMax / eigRatio;
1449 const ST beta = boostFactor_ * lambdaMax;
1450 const ST delta = two / (beta - alpha);
1451 const ST theta = (beta + alpha) / two;
1452 const ST s1 = theta * delta;
1455 *out_ <<
" alpha = " << alpha << endl
1456 <<
" beta = " << beta << endl
1457 <<
" delta = " << delta << endl
1458 <<
" theta = " << theta << endl
1459 <<
" s1 = " << s1 << endl;
1463 Teuchos::RCP<MV> W_ptr = makeTempMultiVector (B);
1467 *out_ <<
" Iteration " << 1 <<
":" << endl
1468 <<
" - \\|D\\|_{\\infty} = " << D_->normInf () << endl;
1472 if (! zeroStartingSolution_) {
1475 if (ck_.is_null ()) {
1476 Teuchos::RCP<const op_type> A_op = A_;
1481 ck_->compute (W, one/theta,
const_cast<V&
> (D_inv),
1482 const_cast<MV&
> (B), X, zero);
1486 firstIterationWithZeroStartingSolution (W, one/theta, D_inv, B, X);
1490 *out_ <<
" - \\|W\\|_{\\infty} = " << maxNormInf (W) << endl
1491 <<
" - \\|X\\|_{\\infty} = " << maxNormInf (X) << endl;
1494 if (numIters > 1 && ck_.is_null ()) {
1495 Teuchos::RCP<const op_type> A_op = A_;
1501 ST rhokp1, dtemp1, dtemp2;
1502 for (
int deg = 1; deg < numIters; ++deg) {
1504 *out_ <<
" Iteration " << deg+1 <<
":" << endl
1505 <<
" - \\|D\\|_{\\infty} = " << D_->normInf () << endl
1506 <<
" - \\|B\\|_{\\infty} = " << maxNormInf (B) << endl
1507 <<
" - \\|A\\|_{\\text{frob}} = " << A_->getFrobeniusNorm ()
1508 << endl <<
" - rhok = " << rhok << endl;
1511 rhokp1 = one / (two * s1 - rhok);
1512 dtemp1 = rhokp1 * rhok;
1513 dtemp2 = two * rhokp1 * delta;
1517 *out_ <<
" - dtemp1 = " << dtemp1 << endl
1518 <<
" - dtemp2 = " << dtemp2 << endl;
1523 ck_->compute (W, dtemp2,
const_cast<V&
> (D_inv),
1524 const_cast<MV&
> (B), (X), dtemp1);
1527 *out_ <<
" - \\|W\\|_{\\infty} = " << maxNormInf (W) << endl
1528 <<
" - \\|X\\|_{\\infty} = " << maxNormInf (X) << endl;
1534template<
class ScalarType,
class MV>
1543 using MagnitudeType =
typename STS::magnitudeType;
1545 *out_ <<
" cgMethodWithInitGuess:" << endl;
1548 const ST one = STS::one();
1549 ST beta, betaOld = one, pAp, pApOld = one, alpha, rHz, rHzOld, rHzOld2 = one, lambdaMax;
1551 Teuchos::ArrayRCP<MagnitudeType> diag, offdiag;
1552 Teuchos::RCP<V> p, z, Ap;
1553 diag.resize(numIters);
1554 offdiag.resize(numIters-1);
1556 p = rcp(
new V(A.getRangeMap ()));
1557 z = rcp(
new V(A.getRangeMap ()));
1558 Ap = rcp(
new V(A.getRangeMap ()));
1561 solve (*p, D_inv, r);
1564 for (
int iter = 0; iter < numIters; ++iter) {
1566 *out_ <<
" Iteration " << iter << endl;
1571 r.update (-alpha, *Ap, one);
1573 solve (*z, D_inv, r);
1575 beta = rHz / rHzOld;
1576 p->update (one, *z, beta);
1578 diag[iter] = STS::real((betaOld*betaOld * pApOld + pAp) / rHzOld);
1579 offdiag[iter-1] = -STS::real((betaOld * pApOld / (sqrt(rHzOld * rHzOld2))));
1581 *out_ <<
" diag[" << iter <<
"] = " << diag[iter] << endl;
1582 *out_ <<
" offdiag["<< iter-1 <<
"] = " << offdiag[iter-1] << endl;
1585 diag[iter] = STS::real(pAp/rHzOld);
1587 *out_ <<
" diag[" << iter <<
"] = " << diag[iter] << endl;
1595 lambdaMax = LapackHelper<ST>::tri_diag_spectral_radius(diag, offdiag);
1601template<
class ScalarType,
class MV>
1604cgMethod (
const op_type& A,
const V& D_inv,
const int numIters)
1608 *out_ <<
"cgMethod:" << endl;
1612 if (eigVector_.is_null()) {
1613 r = rcp(
new V(A.getDomainMap ()));
1614 if (eigKeepVectors_)
1619 PowerMethod::computeInitialGuessForPowerMethod (*r,
false);
1623 ST lambdaMax = cgMethodWithInitGuess (A, D_inv, numIters, *r);
1628template<
class ScalarType,
class MV>
1629Teuchos::RCP<const typename Chebyshev<ScalarType, MV>::row_matrix_type>
1634template<
class ScalarType,
class MV>
1642template<
class ScalarType,
class MV>
1651 const size_t B_numVecs = B.getNumVectors ();
1652 if (W_.is_null () || W_->getNumVectors () != B_numVecs) {
1653 W_ = Teuchos::rcp (
new MV (B.getMap (), B_numVecs,
false));
1658template<
class ScalarType,
class MV>
1660Chebyshev<ScalarType, MV>::
1661makeSecondTempMultiVector (
const MV& B)
1667 const size_t B_numVecs = B.getNumVectors ();
1668 if (W2_.is_null () || W2_->getNumVectors () != B_numVecs) {
1669 W2_ = Teuchos::rcp (
new MV (B.getMap (), B_numVecs,
false));
1675template<
class ScalarType,
class MV>
1679 std::ostringstream oss;
1682 oss <<
"\"Ifpack2::Details::Chebyshev\":"
1684 <<
"degree: " << numIters_
1685 <<
", lambdaMax: " << lambdaMaxForApply_
1686 <<
", alpha: " << eigRatioForApply_
1687 <<
", lambdaMin: " << lambdaMinForApply_
1688 <<
", boost factor: " << boostFactor_
1689 <<
", algorithm: " << chebyshevAlgorithm_;
1690 if (!userInvDiag_.is_null())
1691 oss <<
", diagonal: user-supplied";
1696template<
class ScalarType,
class MV>
1699describe (Teuchos::FancyOStream& out,
1700 const Teuchos::EVerbosityLevel verbLevel)
const
1702 using Teuchos::TypeNameTraits;
1705 const Teuchos::EVerbosityLevel vl =
1706 (verbLevel == Teuchos::VERB_DEFAULT) ? Teuchos::VERB_LOW : verbLevel;
1707 if (vl == Teuchos::VERB_NONE) {
1717 Teuchos::OSTab tab0 (out);
1723 if (A_.is_null () || A_->getComm ().is_null ()) {
1727 myRank = A_->getComm ()->getRank ();
1732 out <<
"\"Ifpack2::Details::Chebyshev\":" << endl;
1734 Teuchos::OSTab tab1 (out);
1736 if (vl == Teuchos::VERB_LOW) {
1738 out <<
"degree: " << numIters_ << endl
1739 <<
"lambdaMax: " << lambdaMaxForApply_ << endl
1740 <<
"alpha: " << eigRatioForApply_ << endl
1741 <<
"lambdaMin: " << lambdaMinForApply_ << endl
1742 <<
"boost factor: " << boostFactor_ << endl;
1750 out <<
"Template parameters:" << endl;
1752 Teuchos::OSTab tab2 (out);
1753 out <<
"ScalarType: " << TypeNameTraits<ScalarType>::name () << endl
1754 <<
"MV: " << TypeNameTraits<MV>::name () << endl;
1760 out <<
"Computed parameters:" << endl;
1766 Teuchos::OSTab tab2 (out);
1772 if (D_.is_null ()) {
1774 out <<
"unset" << endl;
1777 else if (vl <= Teuchos::VERB_HIGH) {
1779 out <<
"set" << endl;
1788 D_->describe (out, vl);
1793 out <<
"W_: " << (W_.is_null () ?
"unset" :
"set") << endl
1794 <<
"computedLambdaMax_: " << computedLambdaMax_ << endl
1795 <<
"computedLambdaMin_: " << computedLambdaMin_ << endl
1796 <<
"lambdaMaxForApply_: " << lambdaMaxForApply_ << endl
1797 <<
"lambdaMinForApply_: " << lambdaMinForApply_ << endl
1798 <<
"eigRatioForApply_: " << eigRatioForApply_ << endl;
1803 out <<
"User parameters:" << endl;
1808 Teuchos::OSTab tab2 (out);
1809 out <<
"userInvDiag_: ";
1810 if (userInvDiag_.is_null ()) {
1811 out <<
"unset" << endl;
1813 else if (vl <= Teuchos::VERB_HIGH) {
1814 out <<
"set" << endl;
1820 userInvDiag_->describe (out, vl);
1823 out <<
"userLambdaMax_: " << userLambdaMax_ << endl
1824 <<
"userLambdaMin_: " << userLambdaMin_ << endl
1825 <<
"userEigRatio_: " << userEigRatio_ << endl
1826 <<
"numIters_: " << numIters_ << endl
1827 <<
"eigMaxIters_: " << eigMaxIters_ << endl
1828 <<
"eigRelTolerance_: " << eigRelTolerance_ << endl
1829 <<
"eigNormalizationFreq_: " << eigNormalizationFreq_ << endl
1830 <<
"zeroStartingSolution_: " << zeroStartingSolution_ << endl
1831 <<
"assumeMatrixUnchanged_: " << assumeMatrixUnchanged_ << endl
1832 <<
"chebyshevAlgorithm_: " << chebyshevAlgorithm_ << endl
1833 <<
"computeMaxResNorm_: " << computeMaxResNorm_ << endl;