326template <
class ScalarType,
class MV>
331 using Teuchos::rcp_const_cast;
397 if (
plist.isType<
bool>(
"debug")) {
399 }
else if (
plist.isType<
int>(
"debug")) {
463 if (
plist.isParameter(
"chebyshev: use native spmv"))
467 if (
plist.isParameter(
"chebyshev: pre-allocate temp vector"))
473 if (
plist.isParameter(
"chebyshev: max eigenvalue")) {
474 if (
plist.isType<
double>(
"chebyshev: max eigenvalue"))
479 STS::isnaninf(
lambdaMax), std::invalid_argument,
480 "Ifpack2::Chebyshev::setParameters: \"chebyshev: max eigenvalue\" "
481 "parameter is NaN or Inf. This parameter is optional, but if you "
482 "choose to supply it, it must have a finite value.");
484 if (
plist.isParameter(
"chebyshev: min eigenvalue")) {
485 if (
plist.isType<
double>(
"chebyshev: min eigenvalue"))
490 STS::isnaninf(
lambdaMin), std::invalid_argument,
491 "Ifpack2::Chebyshev::setParameters: \"chebyshev: min eigenvalue\" "
492 "parameter is NaN or Inf. This parameter is optional, but if you "
493 "choose to supply it, it must have a finite value.");
497 if (
plist.isParameter(
"smoother: Chebyshev alpha")) {
498 if (
plist.isType<
double>(
"smoother: Chebyshev alpha"))
506 STS::isnaninf(
eigRatio), std::invalid_argument,
507 "Ifpack2::Chebyshev::setParameters: \"chebyshev: ratio eigenvalue\" "
508 "parameter (also called \"smoother: Chebyshev alpha\") is NaN or Inf. "
509 "This parameter is optional, but if you choose to supply it, it must have "
517 STS::real(
eigRatio) < STS::real(STS::one()),
518 std::invalid_argument,
519 "Ifpack2::Chebyshev::setParameters: \"chebyshev: ratio eigenvalue\""
520 "parameter (also called \"smoother: Chebyshev alpha\") must be >= 1, "
521 "but you supplied the value "
527 const char paramName[] =
"chebyshev: boost factor";
532 }
else if (!std::is_same<double, MT>::value &&
538 "Ifpack2::Chebyshev::setParameters: \"chebyshev: boost factor\""
539 "parameter must have type magnitude_type (MT) or double.");
551 "Ifpack2::Chebyshev::setParameters: \"" <<
paramName <<
"\" parameter "
552 "must be >= 1, but you supplied the value "
559 STS::isnaninf(
minDiagVal), std::invalid_argument,
560 "Ifpack2::Chebyshev::setParameters: \"chebyshev: min diagonal value\" "
561 "parameter is NaN or Inf. This parameter is optional, but if you choose "
562 "to supply it, it must have a finite value.");
565 if (
plist.isParameter(
"smoother: sweeps")) {
568 if (
plist.isParameter(
"relaxation: sweeps")) {
573 numIters < 0, std::invalid_argument,
574 "Ifpack2::Chebyshev::setParameters: \"chebyshev: degree\" parameter (also "
575 "called \"smoother: sweeps\" or \"relaxation: sweeps\") must be a "
576 "nonnegative integer. You gave a value of "
580 if (
plist.isParameter(
"eigen-analysis: iterations")) {
586 "Ifpack2::Chebyshev::setParameters: \"chebyshev: eigenvalue max iterations"
587 "\" parameter (also called \"eigen-analysis: iterations\") must be a "
588 "nonnegative integer. You gave a value of "
591 if (
plist.isType<
double>(
"chebyshev: eigenvalue relative tolerance"))
592 eigRelTolerance = Teuchos::as<MT>(
plist.get<
double>(
"chebyshev: eigenvalue relative tolerance"));
593 else if (
plist.isType<
MT>(
"chebyshev: eigenvalue relative tolerance"))
595 else if (
plist.isType<
ST>(
"chebyshev: eigenvalue relative tolerance"))
596 eigRelTolerance = Teuchos::ScalarTraits<ST>::magnitude(
plist.get<
ST>(
"chebyshev: eigenvalue relative tolerance"));
603 "Ifpack2::Chebyshev::setParameters: \"chebyshev: eigenvalue normalization frequency"
604 "\" parameter must be a "
605 "nonnegative integer. You gave a value of "
608 zeroStartingSolution =
plist.get(
"chebyshev: zero starting solution",
609 zeroStartingSolution);
615 if (
plist.isParameter(
"chebyshev: algorithm")) {
622 std::invalid_argument,
623 "Ifpack2::Chebyshev: Ifpack2 only supports \"first\", \"textbook\", \"fourth\", and \"opt_fourth\", for \"chebyshev: algorithm\".");
626 if (
plist.isParameter(
"chebyshev: compute max residual norm")) {
629 if (
plist.isParameter(
"chebyshev: compute spectral radius")) {
637 !
plist.get<
bool>(
"chebyshev: use block mode"),
638 std::invalid_argument,
639 "Ifpack2::Chebyshev requires that if you set \"chebyshev: use "
640 "block mode\" at all, you must set it to false. "
641 "Ifpack2::Chebyshev does not implement Ifpack's block mode.");
643 !
plist.get<
bool>(
"chebyshev: solve normal equations"),
644 std::invalid_argument,
645 "Ifpack2::Chebyshev does not and will never implement the Ifpack "
646 "parameter \"chebyshev: solve normal equations\". If you want to "
647 "solve the normal equations, construct a Tpetra::Operator that "
648 "implements A^* A, and use Chebyshev to solve A^* A x = A^* b.");
657 if (
plist.isParameter(
"eigen-analysis: type")) {
663 std::invalid_argument,
664 "Ifpack2::Chebyshev: Ifpack2 only supports \"power method\" and \"cg\" for \"eigen-analysis: type\".");
680 zeroStartingSolution_ = zeroStartingSolution;
692 if (A_.is_null() || A_->getComm().is_null()) {
697 myRank = A_->getComm()->getRank();
701 out_ = Teuchos::getFancyOStream(Teuchos::rcpFromRef(std::cerr));
703 using Teuchos::oblackholestream;
705 out_ = Teuchos::getFancyOStream(
blackHole);
709 out_ = Teuchos::null;
713template <
class ScalarType,
class MV>
717 diagOffsets_ = offsets_type();
718 savedDiagOffsets_ =
false;
720 computedLambdaMax_ = STS::nan();
721 computedLambdaMin_ = STS::nan();
722 eigVector_ = Teuchos::null;
723 eigVector2_ = Teuchos::null;
726template <
class ScalarType,
class MV>
728 setMatrix(
const Teuchos::RCP<const row_matrix_type>& A) {
729 if (A.getRawPtr() != A_.getRawPtr()) {
730 if (!assumeMatrixUnchanged_) {
742 if (A.is_null() || A->getComm().is_null()) {
747 myRank = A->getComm()->getRank();
751 out_ = Teuchos::getFancyOStream(Teuchos::rcpFromRef(std::cerr));
753 Teuchos::RCP<Teuchos::oblackholestream>
blackHole(
new Teuchos::oblackholestream());
754 out_ = Teuchos::getFancyOStream(
blackHole);
758 out_ = Teuchos::null;
763template <
class ScalarType,
class MV>
770 typedef Tpetra::CrsMatrix<
typename MV::scalar_type,
771 typename MV::local_ordinal_type,
772 typename MV::global_ordinal_type,
773 typename MV::node_type>
777 A_.is_null(), std::runtime_error,
778 "Ifpack2::Chebyshev::compute: The input "
779 "matrix A is null. Please call setMatrix() with a nonnull input matrix "
780 "before calling this method.");
795 if (userInvDiag_.is_null()) {
796 Teuchos::RCP<const crs_matrix_type>
A_crsMat =
797 Teuchos::rcp_dynamic_cast<const crs_matrix_type>(A_);
803 diagOffsets_ = offsets_type();
804 diagOffsets_ = offsets_type(
"offsets",
lclNumRows);
806 A_crsMat->getCrsGraph()->getLocalDiagOffsets(diagOffsets_);
807 savedDiagOffsets_ =
true;
808 D_ = makeInverseDiagonal(*A_,
true);
810 D_ = makeInverseDiagonal(*A_);
812 }
else if (!assumeMatrixUnchanged_) {
816 if (!savedDiagOffsets_) {
819 diagOffsets_ = offsets_type();
820 diagOffsets_ = offsets_type(
"offsets",
lclNumRows);
822 A_crsMat->getCrsGraph()->getLocalDiagOffsets(diagOffsets_);
823 savedDiagOffsets_ =
true;
826 D_ = makeInverseDiagonal(*A_,
true);
828 D_ = makeInverseDiagonal(*A_);
832 D_ = makeRangeMapVectorConst(userInvDiag_);
837 STS::isnaninf(computedLambdaMax_) || STS::isnaninf(computedLambdaMin_);
847 if (!assumeMatrixUnchanged_ ||
850 if ((eigenAnalysisType_ ==
"power method") || (eigenAnalysisType_ ==
"power-method")) {
852 if (eigVector_.is_null()) {
853 x = Teuchos::rcp(
new V(A_->getDomainMap()));
856 PowerMethod::computeInitialGuessForPowerMethod(*x,
false);
861 if (eigVector2_.is_null()) {
862 y =
rcp(
new V(A_->getRangeMap()));
868 Teuchos::RCP<Teuchos::FancyOStream> stream = (debug_ ? out_ : Teuchos::null);
869 computedLambdaMax = PowerMethod::powerMethodWithInitGuess(*A_, *D_, eigMaxIters_, x, y,
870 eigRelTolerance_, eigNormalizationFreq_, stream,
871 computeSpectralRadius_);
878 "Ifpack2::Chebyshev::compute: Estimation of the max eigenvalue "
879 "of D^{-1} A failed, by producing Inf or NaN. This probably means that "
880 "the matrix contains Inf or NaN values, or that it is badly scaled.");
882 STS::isnaninf(userEigRatio_),
884 "Ifpack2::Chebyshev::compute: userEigRatio_ is Inf or NaN."
886 <<
"This should be impossible." <<
endl
887 <<
"Please report this bug to the Ifpack2 developers.");
900 STS::isnaninf(userLambdaMax_) && STS::isnaninf(computedLambdaMax_),
902 "Ifpack2::Chebyshev::compute: " <<
endl
903 <<
"Both userLambdaMax_ and computedLambdaMax_ are Inf or NaN."
905 <<
"This should be impossible." <<
endl
906 <<
"Please report this bug to the Ifpack2 developers.");
914 lambdaMaxForApply_ = STS::isnaninf(userLambdaMax_) ? computedLambdaMax_ : userLambdaMax_;
927 lambdaMinForApply_ = lambdaMaxForApply_ / userEigRatio_;
928 eigRatioForApply_ = userEigRatio_;
930 if (chebyshevAlgorithm_ ==
"first") {
933 const ST one = Teuchos::as<ST>(1);
936 if (STS::magnitude(lambdaMaxForApply_ -
one) < Teuchos::as<MT>(1.0e-6)) {
937 lambdaMinForApply_ =
one;
938 lambdaMaxForApply_ = lambdaMinForApply_;
939 eigRatioForApply_ =
one;
944 if (preAllocateTempVector_ && !D_.is_null()) {
945 makeTempMultiVector(*D_);
946 if (chebyshevAlgorithm_ ==
"fourth" || chebyshevAlgorithm_ ==
"opt_fourth") {
947 makeSecondTempMultiVector(*D_);
951 if (chebyshevAlgorithm_ ==
"textbook") {
957 if (ckUseNativeSpMV_) {
958 ck_->setAuxiliaryVectors(1);
963template <
class ScalarType,
class MV>
967 return lambdaMaxForApply_;
970template <
class ScalarType,
class MV>
973 const char prefix[] =
"Ifpack2::Chebyshev::apply: ";
976 *out_ <<
"apply: " << std::endl;
979 " Please call setMatrix() with a nonnull input matrix, and then call "
980 "compute(), before calling this method.");
982 prefix <<
"There is no estimate for the max eigenvalue."
986 prefix <<
"There is no estimate for the min eigenvalue."
990 prefix <<
"There is no estimate for the ratio of the max "
991 "eigenvalue to the min eigenvalue."
995 "diagonal entries of the matrix has not yet been computed."
999 if (chebyshevAlgorithm_ ==
"fourth" || chebyshevAlgorithm_ ==
"opt_fourth") {
1000 fourthKindApplyImpl(*A_, B, X, numIters_, lambdaMaxForApply_, *D_);
1001 }
else if (chebyshevAlgorithm_ ==
"textbook") {
1002 textbookApplyImpl(*A_, B, X, numIters_, lambdaMaxForApply_,
1003 lambdaMinForApply_, eigRatioForApply_, *D_);
1005 ifpackApplyImpl(*A_, B, X, numIters_, lambdaMaxForApply_,
1006 lambdaMinForApply_, eigRatioForApply_, *D_);
1009 if (computeMaxResNorm_ && B.getNumVectors() > 0) {
1010 MV R(B.getMap(), B.getNumVectors());
1011 computeResidual(R, B, *A_, X);
1012 Teuchos::Array<MT>
norms(B.getNumVectors());
1014 return *std::max_element(
norms.begin(),
norms.end());
1016 return Teuchos::ScalarTraits<MT>::zero();
1020template <
class ScalarType,
class MV>
1023 using Teuchos::rcpFromRef;
1025 Teuchos::VERB_MEDIUM);
1028template <
class ScalarType,
class MV>
1036 Tpetra::deep_copy(X, W);
1039template <
class ScalarType,
class MV>
1042 const Teuchos::ETransp mode) {
1043 Tpetra::Details::residual(A, X, B, R);
1046template <
class ScalarType,
class MV>
1047void Chebyshev<ScalarType, MV>::
1048 solve(MV& Z,
const V& D_inv,
const MV& R) {
1049 Z.elementWiseMultiply(STS::one(), D_inv, R, STS::zero());
1052template <
class ScalarType,
class MV>
1053void Chebyshev<ScalarType, MV>::
1054 solve(MV& Z,
const ST alpha,
const V& D_inv,
const MV& R) {
1055 Z.elementWiseMultiply(alpha, D_inv, R, STS::zero());
1058template <
class ScalarType,
class MV>
1059Teuchos::RCP<const typename Chebyshev<ScalarType, MV>::V>
1060Chebyshev<ScalarType, MV>::
1061 makeInverseDiagonal(
const row_matrix_type& A,
const bool useDiagOffsets)
const {
1063 using Teuchos::rcp_dynamic_cast;
1064 using Teuchos::rcpFromRef;
1067 if (!D_.is_null() &&
1068 D_->getMap()->isSameAs(*(A.getRowMap()))) {
1070 *out_ <<
"Reusing pre-existing vector for diagonal extraction" << std::endl;
1071 D_rowMap = Teuchos::rcp_const_cast<V>(D_);
1073 D_rowMap = Teuchos::rcp(
new V(A.getRowMap(),
false));
1075 *out_ <<
"Allocated new vector for diagonal extraction" << std::endl;
1077 if (useDiagOffsets) {
1081 typedef Tpetra::CrsMatrix<
typename MV::scalar_type,
1082 typename MV::local_ordinal_type,
1083 typename MV::global_ordinal_type,
1084 typename MV::node_type>
1086 RCP<const crs_matrix_type> A_crsMat =
1087 rcp_dynamic_cast<const crs_matrix_type>(rcpFromRef(A));
1088 if (!A_crsMat.is_null()) {
1089 TEUCHOS_TEST_FOR_EXCEPTION(
1090 !savedDiagOffsets_, std::logic_error,
1091 "Ifpack2::Details::Chebyshev::makeInverseDiagonal: "
1092 "It is not allowed to call this method with useDiagOffsets=true, "
1093 "if you have not previously saved offsets of diagonal entries. "
1094 "This situation should never arise if this class is used properly. "
1095 "Please report this bug to the Ifpack2 developers.");
1096 A_crsMat->getLocalDiagCopy(*D_rowMap, diagOffsets_);
1101 A.getLocalDiagCopy(*D_rowMap);
1103 RCP<V> D_rangeMap = makeRangeMapVector(D_rowMap);
1109 bool foundNonpositiveValue =
false;
1111 auto D_lcl = D_rangeMap->getLocalViewHost(Tpetra::Access::ReadOnly);
1112 auto D_lcl_1d = Kokkos::subview(D_lcl, Kokkos::ALL(), 0);
1114 typedef typename MV::impl_scalar_type IST;
1115 typedef typename MV::local_ordinal_type LO;
1116 typedef KokkosKernels::ArithTraits<IST> ATS;
1117 typedef KokkosKernels::ArithTraits<typename ATS::mag_type> STM;
1119 const LO lclNumRows =
static_cast<LO
>(D_rangeMap->getLocalLength());
1120 for (LO i = 0; i < lclNumRows; ++i) {
1121 if (STS::real(D_lcl_1d(i)) <= STM::zero()) {
1122 foundNonpositiveValue =
true;
1128 using Teuchos::outArg;
1129 using Teuchos::REDUCE_MIN;
1130 using Teuchos::reduceAll;
1132 const int lclSuccess = foundNonpositiveValue ? 0 : 1;
1133 int gblSuccess = lclSuccess;
1134 if (!D_rangeMap->getMap().is_null() && D_rangeMap->getMap()->getComm().is_null()) {
1135 const Teuchos::Comm<int>& comm = *(D_rangeMap->getMap()->getComm());
1136 reduceAll<int, int>(comm, REDUCE_MIN, lclSuccess, outArg(gblSuccess));
1138 if (gblSuccess == 1) {
1139 *out_ <<
"makeInverseDiagonal: The matrix's diagonal entries all have "
1140 "positive real part (this is good for Chebyshev)."
1143 *out_ <<
"makeInverseDiagonal: The matrix's diagonal has at least one "
1144 "entry with nonpositive real part, on at least one process in the "
1145 "matrix's communicator. This is bad for Chebyshev."
1152 reciprocal_threshold(*D_rangeMap, minDiagVal_);
1153 return Teuchos::rcp_const_cast<const V>(D_rangeMap);
1156template <
class ScalarType,
class MV>
1157Teuchos::RCP<const typename Chebyshev<ScalarType, MV>::V>
1158Chebyshev<ScalarType, MV>::
1159 makeRangeMapVectorConst(
const Teuchos::RCP<const V>& D)
const {
1162 typedef Tpetra::Export<
typename MV::local_ordinal_type,
1163 typename MV::global_ordinal_type,
1164 typename MV::node_type>
1169 TEUCHOS_TEST_FOR_EXCEPTION(
1170 A_.is_null(), std::logic_error,
1171 "Ifpack2::Details::Chebyshev::"
1172 "makeRangeMapVector: The input matrix A is null. Please call setMatrix() "
1173 "with a nonnull input matrix before calling this method. This is probably "
1174 "a bug in Ifpack2; please report this bug to the Ifpack2 developers.");
1175 TEUCHOS_TEST_FOR_EXCEPTION(
1176 D.is_null(), std::logic_error,
1177 "Ifpack2::Details::Chebyshev::"
1178 "makeRangeMapVector: The input Vector D is null. This is probably "
1179 "a bug in Ifpack2; please report this bug to the Ifpack2 developers.");
1181 RCP<const map_type> sourceMap = D->getMap();
1182 RCP<const map_type> rangeMap = A_->getRangeMap();
1183 RCP<const map_type> rowMap = A_->getRowMap();
1185 if (rangeMap->isSameAs(*sourceMap)) {
1190 RCP<const export_type> exporter;
1194 if (sourceMap->isSameAs(*rowMap)) {
1196 exporter = A_->getGraph()->getExporter();
1198 exporter = rcp(
new export_type(sourceMap, rangeMap));
1201 if (exporter.is_null()) {
1204 RCP<V> D_out = rcp(
new V(*D, Teuchos::Copy));
1205 D_out->doExport(*D, *exporter, Tpetra::ADD);
1206 return Teuchos::rcp_const_cast<const V>(D_out);
1211template <
class ScalarType,
class MV>
1212Teuchos::RCP<typename Chebyshev<ScalarType, MV>::V>
1213Chebyshev<ScalarType, MV>::
1214 makeRangeMapVector(
const Teuchos::RCP<V>& D)
const {
1215 using Teuchos::rcp_const_cast;
1216 return rcp_const_cast<V>(makeRangeMapVectorConst(rcp_const_cast<V>(D)));
1219template <
class ScalarType,
class MV>
1220void Chebyshev<ScalarType, MV>::
1221 textbookApplyImpl(
const op_type& A,
1228 const V& D_inv)
const {
1230 const ST myLambdaMin = lambdaMax / eigRatio;
1232 const ST zero = Teuchos::as<ST>(0);
1233 const ST one = Teuchos::as<ST>(1);
1234 const ST two = Teuchos::as<ST>(2);
1235 const ST d = (lambdaMax + myLambdaMin) / two;
1236 const ST c = (lambdaMax - myLambdaMin) / two;
1238 if (zeroStartingSolution_ && numIters > 0) {
1242 MV R(B.getMap(), B.getNumVectors(),
false);
1243 MV P(B.getMap(), B.getNumVectors(),
false);
1244 MV Z(B.getMap(), B.getNumVectors(),
false);
1246 for (
int i = 0; i < numIters; ++i) {
1247 computeResidual(R, B, A, X);
1256 beta = alpha * (c / two) * (c / two);
1257 alpha = one / (d - beta);
1258 P.update(one, Z, beta);
1260 X.update(alpha, P, one);
1267template <
class ScalarType,
class MV>
1268void Chebyshev<ScalarType, MV>::
1269 fourthKindApplyImpl(
const op_type& A,
1276 std::vector<ScalarType> betas(numIters, 1.0);
1277 if (chebyshevAlgorithm_ ==
"opt_fourth") {
1278 betas = optimalWeightsImpl<ScalarType>(numIters);
1281 const ST invEig = MT(1) / (lambdaMax * boostFactor_);
1284 Teuchos::RCP<MV> Z_ptr = makeTempMultiVector(B);
1289 Teuchos::RCP<MV> X4_ptr = makeSecondTempMultiVector(B);
1293 if (!zeroStartingSolution_) {
1295 Tpetra::deep_copy(X4, X);
1297 if (ck_.is_null()) {
1298 Teuchos::RCP<const op_type> A_op = A_;
1299 ck_ = Teuchos::rcp(
new ChebyshevKernel<op_type>(A_op, ckUseNativeSpMV_));
1303 ck_->compute(Z, MT(4.0 / 3.0) * invEig,
const_cast<V&
>(D_inv),
1304 const_cast<MV&
>(B), X4, STS::zero());
1307 X.update(betas[0], Z, STS::one());
1310 firstIterationWithZeroStartingSolution(Z, MT(4.0 / 3.0) * invEig, D_inv, B, X4);
1313 X.update(betas[0], Z, STS::zero());
1316 if (numIters > 1 && ck_.is_null()) {
1317 Teuchos::RCP<const op_type> A_op = A_;
1318 ck_ = Teuchos::rcp(
new ChebyshevKernel<op_type>(A_op, ckUseNativeSpMV_));
1321 for (
int i = 1; i < numIters; ++i) {
1322 const ST zScale = (2.0 * i - 1.0) / (2.0 * i + 3.0);
1323 const ST rScale = MT((8.0 * i + 4.0) / (2.0 * i + 3.0)) * invEig;
1327 ck_->compute(Z, rScale,
const_cast<V&
>(D_inv),
1328 const_cast<MV&
>(B), (X4), zScale);
1331 X.update(betas[i], Z, STS::one());
1335template <
class ScalarType,
class MV>
1337Chebyshev<ScalarType, MV>::maxNormInf(
const MV& X) {
1338 Teuchos::Array<MT> norms(X.getNumVectors());
1340 return *std::max_element(norms.begin(), norms.end());
1343template <
class ScalarType,
class MV>
1344void Chebyshev<ScalarType, MV>::
1345 ifpackApplyImpl(
const op_type& A,
1354#ifdef HAVE_IFPACK2_DEBUG
1355 const bool debug = debug_;
1357 const bool debug =
false;
1361 *out_ <<
" \\|B\\|_{\\infty} = " << maxNormInf(B) << endl;
1362 *out_ <<
" \\|X\\|_{\\infty} = " << maxNormInf(X) << endl;
1365 if (numIters <= 0) {
1368 const ST zero =
static_cast<ST
>(0.0);
1369 const ST one =
static_cast<ST
>(1.0);
1370 const ST two =
static_cast<ST
>(2.0);
1373 if (lambdaMin == one && lambdaMax == lambdaMin) {
1379 const ST alpha = lambdaMax / eigRatio;
1380 const ST beta = boostFactor_ * lambdaMax;
1381 const ST delta = two / (beta - alpha);
1382 const ST theta = (beta + alpha) / two;
1383 const ST s1 = theta * delta;
1386 *out_ <<
" alpha = " << alpha << endl
1387 <<
" beta = " << beta << endl
1388 <<
" delta = " << delta << endl
1389 <<
" theta = " << theta << endl
1390 <<
" s1 = " << s1 << endl;
1394 Teuchos::RCP<MV> W_ptr = makeTempMultiVector(B);
1398 *out_ <<
" Iteration " << 1 <<
":" << endl
1399 <<
" - \\|D\\|_{\\infty} = " << D_->normInf() << endl;
1403 if (!zeroStartingSolution_) {
1406 if (ck_.is_null()) {
1407 Teuchos::RCP<const op_type> A_op = A_;
1408 ck_ = Teuchos::rcp(
new ChebyshevKernel<op_type>(A_op, ckUseNativeSpMV_));
1412 ck_->compute(W, one / theta,
const_cast<V&
>(D_inv),
1413 const_cast<MV&
>(B), X, zero);
1416 firstIterationWithZeroStartingSolution(W, one / theta, D_inv, B, X);
1420 *out_ <<
" - \\|W\\|_{\\infty} = " << maxNormInf(W) << endl
1421 <<
" - \\|X\\|_{\\infty} = " << maxNormInf(X) << endl;
1424 if (numIters > 1 && ck_.is_null()) {
1425 Teuchos::RCP<const op_type> A_op = A_;
1426 ck_ = Teuchos::rcp(
new ChebyshevKernel<op_type>(A_op, ckUseNativeSpMV_));
1431 ST rhokp1, dtemp1, dtemp2;
1432 for (
int deg = 1; deg < numIters; ++deg) {
1434 *out_ <<
" Iteration " << deg + 1 <<
":" << endl
1435 <<
" - \\|D\\|_{\\infty} = " << D_->normInf() << endl
1436 <<
" - \\|B\\|_{\\infty} = " << maxNormInf(B) << endl
1437 <<
" - \\|A\\|_{\\text{frob}} = " << A_->getFrobeniusNorm()
1439 <<
" - rhok = " << rhok << endl;
1442 rhokp1 = one / (two * s1 - rhok);
1443 dtemp1 = rhokp1 * rhok;
1444 dtemp2 = two * rhokp1 * delta;
1448 *out_ <<
" - dtemp1 = " << dtemp1 << endl
1449 <<
" - dtemp2 = " << dtemp2 << endl;
1454 ck_->compute(W, dtemp2,
const_cast<V&
>(D_inv),
1455 const_cast<MV&
>(B), (X), dtemp1);
1458 *out_ <<
" - \\|W\\|_{\\infty} = " << maxNormInf(W) << endl
1459 <<
" - \\|X\\|_{\\infty} = " << maxNormInf(X) << endl;
1464template <
class ScalarType,
class MV>
1466Chebyshev<ScalarType, MV>::
1467 cgMethodWithInitGuess(
const op_type& A,
1472 using MagnitudeType =
typename STS::magnitudeType;
1474 *out_ <<
" cgMethodWithInitGuess:" << endl;
1477 const ST one = STS::one();
1478 ST beta, betaOld = one, pAp, pApOld = one, alpha, rHz, rHzOld, rHzOld2 = one, lambdaMax;
1480 Teuchos::ArrayRCP<MagnitudeType> diag, offdiag;
1481 Teuchos::RCP<V> p, z, Ap;
1482 diag.resize(numIters);
1483 offdiag.resize(numIters - 1);
1485 p = rcp(
new V(A.getRangeMap()));
1486 z = rcp(
new V(A.getRangeMap()));
1487 Ap = rcp(
new V(A.getRangeMap()));
1490 solve(*p, D_inv, r);
1493 for (
int iter = 0; iter < numIters; ++iter) {
1495 *out_ <<
" Iteration " << iter << endl;
1500 r.update(-alpha, *Ap, one);
1502 solve(*z, D_inv, r);
1504 beta = rHz / rHzOld;
1505 p->update(one, *z, beta);
1507 diag[iter] = STS::real((betaOld * betaOld * pApOld + pAp) / rHzOld);
1508 offdiag[iter - 1] = -STS::real((betaOld * pApOld / (sqrt(rHzOld * rHzOld2))));
1510 *out_ <<
" diag[" << iter <<
"] = " << diag[iter] << endl;
1511 *out_ <<
" offdiag[" << iter - 1 <<
"] = " << offdiag[iter - 1] << endl;
1512 *out_ <<
" rHz = " << rHz << endl;
1513 *out_ <<
" alpha = " << alpha << endl;
1514 *out_ <<
" beta = " << beta << endl;
1517 diag[iter] = STS::real(pAp / rHzOld);
1519 *out_ <<
" diag[" << iter <<
"] = " << diag[iter] << endl;
1520 *out_ <<
" rHz = " << rHz << endl;
1521 *out_ <<
" alpha = " << alpha << endl;
1522 *out_ <<
" beta = " << beta << endl;
1530 lambdaMax = LapackHelper<ST>::tri_diag_spectral_radius(diag, offdiag);
1535template <
class ScalarType,
class MV>
1537Chebyshev<ScalarType, MV>::
1538 cgMethod(
const op_type& A,
const V& D_inv,
const int numIters) {
1542 *out_ <<
"cgMethod:" << endl;
1546 if (eigVector_.is_null()) {
1547 r = rcp(
new V(A.getDomainMap()));
1548 if (eigKeepVectors_)
1551 Details::computeInitialGuessForCG(D_inv, *r);
1555 ST lambdaMax = cgMethodWithInitGuess(A, D_inv, numIters, *r);
1560template <
class ScalarType,
class MV>
1561Teuchos::RCP<const typename Chebyshev<ScalarType, MV>::row_matrix_type>
1566template <
class ScalarType,
class MV>
1573template <
class ScalarType,
class MV>
1581 const size_t B_numVecs = B.getNumVectors();
1582 if (W_.is_null() || W_->getNumVectors() !=
B_numVecs) {
1583 W_ = Teuchos::rcp(
new MV(B.getMap(),
B_numVecs,
false));
1588template <
class ScalarType,
class MV>
1590Chebyshev<ScalarType, MV>::
1591 makeSecondTempMultiVector(
const MV& B) {
1596 const size_t B_numVecs = B.getNumVectors();
1597 if (W2_.is_null() || W2_->getNumVectors() != B_numVecs) {
1598 W2_ = Teuchos::rcp(
new MV(B.getMap(), B_numVecs,
false));
1603template <
class ScalarType,
class MV>
1607 std::ostringstream
oss;
1610 oss <<
"\"Ifpack2::Details::Chebyshev\":"
1612 <<
"degree: " << numIters_
1613 <<
", lambdaMax: " << lambdaMaxForApply_
1614 <<
", alpha: " << eigRatioForApply_
1615 <<
", lambdaMin: " << lambdaMinForApply_
1616 <<
", boost factor: " << boostFactor_
1617 <<
", algorithm: " << chebyshevAlgorithm_;
1618 if (!userInvDiag_.is_null())
1619 oss <<
", diagonal: user-supplied";
1624template <
class ScalarType,
class MV>
1627 const Teuchos::EVerbosityLevel
verbLevel)
const {
1629 using Teuchos::TypeNameTraits;
1631 const Teuchos::EVerbosityLevel
vl =
1633 if (
vl == Teuchos::VERB_NONE) {
1649 if (A_.is_null() || A_->getComm().is_null()) {
1652 myRank = A_->getComm()->getRank();
1657 out <<
"\"Ifpack2::Details::Chebyshev\":" <<
endl;
1661 if (
vl == Teuchos::VERB_LOW) {
1663 out <<
"degree: " << numIters_ <<
endl
1664 <<
"lambdaMax: " << lambdaMaxForApply_ <<
endl
1665 <<
"alpha: " << eigRatioForApply_ <<
endl
1666 <<
"lambdaMin: " << lambdaMinForApply_ <<
endl
1667 <<
"boost factor: " << boostFactor_ <<
endl;
1675 out <<
"Template parameters:" <<
endl;
1685 out <<
"Computed parameters:" <<
endl;
1701 }
else if (
vl <= Teuchos::VERB_HIGH) {
1716 out <<
"W_: " << (W_.is_null() ?
"unset" :
"set") <<
endl
1717 <<
"computedLambdaMax_: " << computedLambdaMax_ <<
endl
1718 <<
"computedLambdaMin_: " << computedLambdaMin_ <<
endl
1719 <<
"lambdaMaxForApply_: " << lambdaMaxForApply_ <<
endl
1720 <<
"lambdaMinForApply_: " << lambdaMinForApply_ <<
endl
1721 <<
"eigRatioForApply_: " << eigRatioForApply_ <<
endl;
1726 out <<
"User parameters:" <<
endl;
1732 out <<
"userInvDiag_: ";
1733 if (userInvDiag_.is_null()) {
1735 }
else if (
vl <= Teuchos::VERB_HIGH) {
1744 out <<
"userLambdaMax_: " << userLambdaMax_ <<
endl
1745 <<
"userLambdaMin_: " << userLambdaMin_ <<
endl
1746 <<
"userEigRatio_: " << userEigRatio_ <<
endl
1747 <<
"numIters_: " << numIters_ <<
endl
1748 <<
"eigMaxIters_: " << eigMaxIters_ <<
endl
1749 <<
"eigRelTolerance_: " << eigRelTolerance_ <<
endl
1750 <<
"eigNormalizationFreq_: " << eigNormalizationFreq_ <<
endl
1751 <<
"zeroStartingSolution_: " << zeroStartingSolution_ <<
endl
1752 <<
"assumeMatrixUnchanged_: " << assumeMatrixUnchanged_ <<
endl
1753 <<
"chebyshevAlgorithm_: " << chebyshevAlgorithm_ <<
endl
1754 <<
"computeMaxResNorm_: " << computeMaxResNorm_ <<
endl;