323 checkConstructorInput();
327template <
class ScalarType,
class MV>
332 using Teuchos::rcp_const_cast;
398 if (
plist.isType<
bool>(
"debug")) {
399 debug =
plist.get<
bool>(
"debug");
400 }
else if (
plist.isType<
int>(
"debug")) {
464 if (
plist.isParameter(
"chebyshev: use native spmv"))
468 if (
plist.isParameter(
"chebyshev: pre-allocate temp vector"))
474 if (
plist.isParameter(
"chebyshev: max eigenvalue")) {
475 if (
plist.isType<
double>(
"chebyshev: max eigenvalue"))
480 STS::isnaninf(
lambdaMax), std::invalid_argument,
481 "Ifpack2::Chebyshev::setParameters: \"chebyshev: max eigenvalue\" "
482 "parameter is NaN or Inf. This parameter is optional, but if you "
483 "choose to supply it, it must have a finite value.");
485 if (
plist.isParameter(
"chebyshev: min eigenvalue")) {
486 if (
plist.isType<
double>(
"chebyshev: min eigenvalue"))
491 STS::isnaninf(
lambdaMin), std::invalid_argument,
492 "Ifpack2::Chebyshev::setParameters: \"chebyshev: min eigenvalue\" "
493 "parameter is NaN or Inf. This parameter is optional, but if you "
494 "choose to supply it, it must have a finite value.");
498 if (
plist.isParameter(
"smoother: Chebyshev alpha")) {
499 if (
plist.isType<
double>(
"smoother: Chebyshev alpha"))
507 STS::isnaninf(
eigRatio), std::invalid_argument,
508 "Ifpack2::Chebyshev::setParameters: \"chebyshev: ratio eigenvalue\" "
509 "parameter (also called \"smoother: Chebyshev alpha\") is NaN or Inf. "
510 "This parameter is optional, but if you choose to supply it, it must have "
518 STS::real(
eigRatio) < STS::real(STS::one()),
519 std::invalid_argument,
520 "Ifpack2::Chebyshev::setParameters: \"chebyshev: ratio eigenvalue\""
521 "parameter (also called \"smoother: Chebyshev alpha\") must be >= 1, "
522 "but you supplied the value "
528 const char paramName[] =
"chebyshev: boost factor";
533 }
else if (!std::is_same<double, MT>::value &&
539 "Ifpack2::Chebyshev::setParameters: \"chebyshev: boost factor\""
540 "parameter must have type magnitude_type (MT) or double.");
552 "Ifpack2::Chebyshev::setParameters: \"" <<
paramName <<
"\" parameter "
553 "must be >= 1, but you supplied the value "
560 STS::isnaninf(
minDiagVal), std::invalid_argument,
561 "Ifpack2::Chebyshev::setParameters: \"chebyshev: min diagonal value\" "
562 "parameter is NaN or Inf. This parameter is optional, but if you choose "
563 "to supply it, it must have a finite value.");
566 if (
plist.isParameter(
"smoother: sweeps")) {
569 if (
plist.isParameter(
"relaxation: sweeps")) {
574 numIters < 0, std::invalid_argument,
575 "Ifpack2::Chebyshev::setParameters: \"chebyshev: degree\" parameter (also "
576 "called \"smoother: sweeps\" or \"relaxation: sweeps\") must be a "
577 "nonnegative integer. You gave a value of "
581 if (
plist.isParameter(
"eigen-analysis: iterations")) {
587 "Ifpack2::Chebyshev::setParameters: \"chebyshev: eigenvalue max iterations"
588 "\" parameter (also called \"eigen-analysis: iterations\") must be a "
589 "nonnegative integer. You gave a value of "
592 if (
plist.isType<
double>(
"chebyshev: eigenvalue relative tolerance"))
593 eigRelTolerance = Teuchos::as<MT>(
plist.get<
double>(
"chebyshev: eigenvalue relative tolerance"));
594 else if (
plist.isType<
MT>(
"chebyshev: eigenvalue relative tolerance"))
596 else if (
plist.isType<
ST>(
"chebyshev: eigenvalue relative tolerance"))
597 eigRelTolerance = Teuchos::ScalarTraits<ST>::magnitude(
plist.get<
ST>(
"chebyshev: eigenvalue relative tolerance"));
604 "Ifpack2::Chebyshev::setParameters: \"chebyshev: eigenvalue normalization frequency"
605 "\" parameter must be a "
606 "nonnegative integer. You gave a value of "
609 zeroStartingSolution =
plist.get(
"chebyshev: zero starting solution",
610 zeroStartingSolution);
616 if (
plist.isParameter(
"chebyshev: algorithm")) {
623 std::invalid_argument,
624 "Ifpack2::Chebyshev: Ifpack2 only supports \"first\", \"textbook\", \"fourth\", and \"opt_fourth\", for \"chebyshev: algorithm\".");
627 if (
plist.isParameter(
"chebyshev: compute max residual norm")) {
630 if (
plist.isParameter(
"chebyshev: compute spectral radius")) {
638 !
plist.get<
bool>(
"chebyshev: use block mode"),
639 std::invalid_argument,
640 "Ifpack2::Chebyshev requires that if you set \"chebyshev: use "
641 "block mode\" at all, you must set it to false. "
642 "Ifpack2::Chebyshev does not implement Ifpack's block mode.");
644 !
plist.get<
bool>(
"chebyshev: solve normal equations"),
645 std::invalid_argument,
646 "Ifpack2::Chebyshev does not and will never implement the Ifpack "
647 "parameter \"chebyshev: solve normal equations\". If you want to "
648 "solve the normal equations, construct a Tpetra::Operator that "
649 "implements A^* A, and use Chebyshev to solve A^* A x = A^* b.");
658 if (
plist.isParameter(
"eigen-analysis: type")) {
664 std::invalid_argument,
665 "Ifpack2::Chebyshev: Ifpack2 only supports \"power method\" and \"cg\" for \"eigen-analysis: type\".");
681 zeroStartingSolution_ = zeroStartingSolution;
693 if (A_.is_null() || A_->getComm().is_null()) {
698 myRank = A_->getComm()->getRank();
702 out_ = Teuchos::getFancyOStream(Teuchos::rcpFromRef(std::cerr));
704 using Teuchos::oblackholestream;
706 out_ = Teuchos::getFancyOStream(
blackHole);
710 out_ = Teuchos::null;
714template <
class ScalarType,
class MV>
718 diagOffsets_ = offsets_type();
719 savedDiagOffsets_ =
false;
721 computedLambdaMax_ = STS::nan();
722 computedLambdaMin_ = STS::nan();
723 eigVector_ = Teuchos::null;
724 eigVector2_ = Teuchos::null;
727template <
class ScalarType,
class MV>
729 setMatrix(
const Teuchos::RCP<const row_matrix_type>& A) {
730 if (A.getRawPtr() != A_.getRawPtr()) {
731 if (!assumeMatrixUnchanged_) {
743 if (A.is_null() || A->getComm().is_null()) {
748 myRank = A->getComm()->getRank();
752 out_ = Teuchos::getFancyOStream(Teuchos::rcpFromRef(std::cerr));
754 Teuchos::RCP<Teuchos::oblackholestream>
blackHole(
new Teuchos::oblackholestream());
755 out_ = Teuchos::getFancyOStream(
blackHole);
759 out_ = Teuchos::null;
764template <
class ScalarType,
class MV>
771 typedef Tpetra::CrsMatrix<
typename MV::scalar_type,
772 typename MV::local_ordinal_type,
773 typename MV::global_ordinal_type,
774 typename MV::node_type>
778 A_.is_null(), std::runtime_error,
779 "Ifpack2::Chebyshev::compute: The input "
780 "matrix A is null. Please call setMatrix() with a nonnull input matrix "
781 "before calling this method.");
796 if (userInvDiag_.is_null()) {
797 Teuchos::RCP<const crs_matrix_type>
A_crsMat =
798 Teuchos::rcp_dynamic_cast<const crs_matrix_type>(A_);
804 diagOffsets_ = offsets_type();
805 diagOffsets_ = offsets_type(
"offsets",
lclNumRows);
807 A_crsMat->getCrsGraph()->getLocalDiagOffsets(diagOffsets_);
808 savedDiagOffsets_ =
true;
809 D_ = makeInverseDiagonal(*A_,
true);
811 D_ = makeInverseDiagonal(*A_);
813 }
else if (!assumeMatrixUnchanged_) {
817 if (!savedDiagOffsets_) {
820 diagOffsets_ = offsets_type();
821 diagOffsets_ = offsets_type(
"offsets",
lclNumRows);
823 A_crsMat->getCrsGraph()->getLocalDiagOffsets(diagOffsets_);
824 savedDiagOffsets_ =
true;
827 D_ = makeInverseDiagonal(*A_,
true);
829 D_ = makeInverseDiagonal(*A_);
833 D_ = makeRangeMapVectorConst(userInvDiag_);
838 STS::isnaninf(computedLambdaMax_) || STS::isnaninf(computedLambdaMin_);
848 if (!assumeMatrixUnchanged_ ||
851 if ((eigenAnalysisType_ ==
"power method") || (eigenAnalysisType_ ==
"power-method")) {
853 if (eigVector_.is_null()) {
854 x = Teuchos::rcp(
new V(A_->getDomainMap()));
857 PowerMethod::computeInitialGuessForPowerMethod(*x,
false);
862 if (eigVector2_.is_null()) {
863 y =
rcp(
new V(A_->getRangeMap()));
869 Teuchos::RCP<Teuchos::FancyOStream> stream = (debug_ ? out_ : Teuchos::null);
870 computedLambdaMax = PowerMethod::powerMethodWithInitGuess(*A_, *D_, eigMaxIters_, x, y,
871 eigRelTolerance_, eigNormalizationFreq_, stream,
872 computeSpectralRadius_);
879 "Ifpack2::Chebyshev::compute: Estimation of the max eigenvalue "
880 "of D^{-1} A failed, by producing Inf or NaN. This probably means that "
881 "the matrix contains Inf or NaN values, or that it is badly scaled.");
883 STS::isnaninf(userEigRatio_),
885 "Ifpack2::Chebyshev::compute: userEigRatio_ is Inf or NaN."
887 <<
"This should be impossible." <<
endl
888 <<
"Please report this bug to the Ifpack2 developers.");
901 STS::isnaninf(userLambdaMax_) && STS::isnaninf(computedLambdaMax_),
903 "Ifpack2::Chebyshev::compute: " <<
endl
904 <<
"Both userLambdaMax_ and computedLambdaMax_ are Inf or NaN."
906 <<
"This should be impossible." <<
endl
907 <<
"Please report this bug to the Ifpack2 developers.");
915 lambdaMaxForApply_ = STS::isnaninf(userLambdaMax_) ? computedLambdaMax_ : userLambdaMax_;
928 lambdaMinForApply_ = lambdaMaxForApply_ / userEigRatio_;
929 eigRatioForApply_ = userEigRatio_;
931 if (chebyshevAlgorithm_ ==
"first") {
934 const ST one = Teuchos::as<ST>(1);
937 if (STS::magnitude(lambdaMaxForApply_ -
one) < Teuchos::as<MT>(1.0e-6)) {
938 lambdaMinForApply_ =
one;
939 lambdaMaxForApply_ = lambdaMinForApply_;
940 eigRatioForApply_ =
one;
945 if (preAllocateTempVector_ && !D_.is_null()) {
946 makeTempMultiVector(*D_);
947 if (chebyshevAlgorithm_ ==
"fourth" || chebyshevAlgorithm_ ==
"opt_fourth") {
948 makeSecondTempMultiVector(*D_);
952 if (chebyshevAlgorithm_ ==
"textbook") {
958 if (ckUseNativeSpMV_) {
959 ck_->setAuxiliaryVectors(1);
964template <
class ScalarType,
class MV>
968 return lambdaMaxForApply_;
971template <
class ScalarType,
class MV>
974 const char prefix[] =
"Ifpack2::Chebyshev::apply: ";
977 *out_ <<
"apply: " << std::endl;
980 " Please call setMatrix() with a nonnull input matrix, and then call "
981 "compute(), before calling this method.");
983 prefix <<
"There is no estimate for the max eigenvalue."
987 prefix <<
"There is no estimate for the min eigenvalue."
991 prefix <<
"There is no estimate for the ratio of the max "
992 "eigenvalue to the min eigenvalue."
996 "diagonal entries of the matrix has not yet been computed."
1000 if (chebyshevAlgorithm_ ==
"fourth" || chebyshevAlgorithm_ ==
"opt_fourth") {
1001 fourthKindApplyImpl(*A_, B, X, numIters_, lambdaMaxForApply_, *D_);
1002 }
else if (chebyshevAlgorithm_ ==
"textbook") {
1003 textbookApplyImpl(*A_, B, X, numIters_, lambdaMaxForApply_,
1004 lambdaMinForApply_, eigRatioForApply_, *D_);
1006 ifpackApplyImpl(*A_, B, X, numIters_, lambdaMaxForApply_,
1007 lambdaMinForApply_, eigRatioForApply_, *D_);
1010 if (computeMaxResNorm_ && B.getNumVectors() > 0) {
1011 MV R(B.getMap(), B.getNumVectors());
1012 computeResidual(R, B, *A_, X);
1013 Teuchos::Array<MT>
norms(B.getNumVectors());
1015 return *std::max_element(
norms.begin(),
norms.end());
1017 return Teuchos::ScalarTraits<MT>::zero();
1021template <
class ScalarType,
class MV>
1024 using Teuchos::rcpFromRef;
1026 Teuchos::VERB_MEDIUM);
1029template <
class ScalarType,
class MV>
1037 Tpetra::deep_copy(X, W);
1040template <
class ScalarType,
class MV>
1043 const Teuchos::ETransp mode) {
1044 Tpetra::Details::residual(A, X, B, R);
1047template <
class ScalarType,
class MV>
1048void Chebyshev<ScalarType, MV>::
1049 solve(MV& Z,
const V& D_inv,
const MV& R) {
1050 Z.elementWiseMultiply(STS::one(), D_inv, R, STS::zero());
1053template <
class ScalarType,
class MV>
1054void Chebyshev<ScalarType, MV>::
1055 solve(MV& Z,
const ST alpha,
const V& D_inv,
const MV& R) {
1056 Z.elementWiseMultiply(alpha, D_inv, R, STS::zero());
1059template <
class ScalarType,
class MV>
1060Teuchos::RCP<const typename Chebyshev<ScalarType, MV>::V>
1061Chebyshev<ScalarType, MV>::
1062 makeInverseDiagonal(
const row_matrix_type& A,
const bool useDiagOffsets)
const {
1064 using Teuchos::rcp_dynamic_cast;
1065 using Teuchos::rcpFromRef;
1068 if (!D_.is_null() &&
1069 D_->getMap()->isSameAs(*(A.getRowMap()))) {
1071 *out_ <<
"Reusing pre-existing vector for diagonal extraction" << std::endl;
1072 D_rowMap = Teuchos::rcp_const_cast<V>(D_);
1074 D_rowMap = Teuchos::rcp(
new V(A.getRowMap(),
false));
1076 *out_ <<
"Allocated new vector for diagonal extraction" << std::endl;
1078 if (useDiagOffsets) {
1082 typedef Tpetra::CrsMatrix<
typename MV::scalar_type,
1083 typename MV::local_ordinal_type,
1084 typename MV::global_ordinal_type,
1085 typename MV::node_type>
1087 RCP<const crs_matrix_type> A_crsMat =
1088 rcp_dynamic_cast<const crs_matrix_type>(rcpFromRef(A));
1089 if (!A_crsMat.is_null()) {
1090 TEUCHOS_TEST_FOR_EXCEPTION(
1091 !savedDiagOffsets_, std::logic_error,
1092 "Ifpack2::Details::Chebyshev::makeInverseDiagonal: "
1093 "It is not allowed to call this method with useDiagOffsets=true, "
1094 "if you have not previously saved offsets of diagonal entries. "
1095 "This situation should never arise if this class is used properly. "
1096 "Please report this bug to the Ifpack2 developers.");
1097 A_crsMat->getLocalDiagCopy(*D_rowMap, diagOffsets_);
1102 A.getLocalDiagCopy(*D_rowMap);
1104 RCP<V> D_rangeMap = makeRangeMapVector(D_rowMap);
1110 bool foundNonpositiveValue =
false;
1112 auto D_lcl = D_rangeMap->getLocalViewHost(Tpetra::Access::ReadOnly);
1113 auto D_lcl_1d = Kokkos::subview(D_lcl, Kokkos::ALL(), 0);
1115 typedef typename MV::impl_scalar_type IST;
1116 typedef typename MV::local_ordinal_type LO;
1117 typedef KokkosKernels::ArithTraits<IST> ATS;
1118 typedef KokkosKernels::ArithTraits<typename ATS::mag_type> STM;
1120 const LO lclNumRows =
static_cast<LO
>(D_rangeMap->getLocalLength());
1121 for (LO i = 0; i < lclNumRows; ++i) {
1122 if (STS::real(D_lcl_1d(i)) <= STM::zero()) {
1123 foundNonpositiveValue =
true;
1129 using Teuchos::outArg;
1130 using Teuchos::REDUCE_MIN;
1131 using Teuchos::reduceAll;
1133 const int lclSuccess = foundNonpositiveValue ? 0 : 1;
1134 int gblSuccess = lclSuccess;
1135 if (!D_rangeMap->getMap().is_null() && D_rangeMap->getMap()->getComm().is_null()) {
1136 const Teuchos::Comm<int>& comm = *(D_rangeMap->getMap()->getComm());
1137 reduceAll<int, int>(comm, REDUCE_MIN, lclSuccess, outArg(gblSuccess));
1139 if (gblSuccess == 1) {
1140 *out_ <<
"makeInverseDiagonal: The matrix's diagonal entries all have "
1141 "positive real part (this is good for Chebyshev)."
1144 *out_ <<
"makeInverseDiagonal: The matrix's diagonal has at least one "
1145 "entry with nonpositive real part, on at least one process in the "
1146 "matrix's communicator. This is bad for Chebyshev."
1153 reciprocal_threshold(*D_rangeMap, minDiagVal_);
1154 return Teuchos::rcp_const_cast<const V>(D_rangeMap);
1157template <
class ScalarType,
class MV>
1158Teuchos::RCP<const typename Chebyshev<ScalarType, MV>::V>
1159Chebyshev<ScalarType, MV>::
1160 makeRangeMapVectorConst(
const Teuchos::RCP<const V>& D)
const {
1163 typedef Tpetra::Export<
typename MV::local_ordinal_type,
1164 typename MV::global_ordinal_type,
1165 typename MV::node_type>
1170 TEUCHOS_TEST_FOR_EXCEPTION(
1171 A_.is_null(), std::logic_error,
1172 "Ifpack2::Details::Chebyshev::"
1173 "makeRangeMapVector: The input matrix A is null. Please call setMatrix() "
1174 "with a nonnull input matrix before calling this method. This is probably "
1175 "a bug in Ifpack2; please report this bug to the Ifpack2 developers.");
1176 TEUCHOS_TEST_FOR_EXCEPTION(
1177 D.is_null(), std::logic_error,
1178 "Ifpack2::Details::Chebyshev::"
1179 "makeRangeMapVector: The input Vector D is null. This is probably "
1180 "a bug in Ifpack2; please report this bug to the Ifpack2 developers.");
1182 RCP<const map_type> sourceMap = D->getMap();
1183 RCP<const map_type> rangeMap = A_->getRangeMap();
1184 RCP<const map_type> rowMap = A_->getRowMap();
1186 if (rangeMap->isSameAs(*sourceMap)) {
1191 RCP<const export_type> exporter;
1195 if (sourceMap->isSameAs(*rowMap)) {
1197 exporter = A_->getGraph()->getExporter();
1199 exporter = rcp(
new export_type(sourceMap, rangeMap));
1202 if (exporter.is_null()) {
1205 RCP<V> D_out = rcp(
new V(*D, Teuchos::Copy));
1206 D_out->doExport(*D, *exporter, Tpetra::ADD);
1207 return Teuchos::rcp_const_cast<const V>(D_out);
1212template <
class ScalarType,
class MV>
1213Teuchos::RCP<typename Chebyshev<ScalarType, MV>::V>
1214Chebyshev<ScalarType, MV>::
1215 makeRangeMapVector(
const Teuchos::RCP<V>& D)
const {
1216 using Teuchos::rcp_const_cast;
1217 return rcp_const_cast<V>(makeRangeMapVectorConst(rcp_const_cast<V>(D)));
1220template <
class ScalarType,
class MV>
1221void Chebyshev<ScalarType, MV>::
1222 textbookApplyImpl(
const op_type& A,
1229 const V& D_inv)
const {
1231 const ST myLambdaMin = lambdaMax / eigRatio;
1233 const ST zero = Teuchos::as<ST>(0);
1234 const ST one = Teuchos::as<ST>(1);
1235 const ST two = Teuchos::as<ST>(2);
1236 const ST d = (lambdaMax + myLambdaMin) / two;
1237 const ST c = (lambdaMax - myLambdaMin) / two;
1239 if (zeroStartingSolution_ && numIters > 0) {
1243 MV R(B.getMap(), B.getNumVectors(),
false);
1244 MV P(B.getMap(), B.getNumVectors(),
false);
1245 MV Z(B.getMap(), B.getNumVectors(),
false);
1247 for (
int i = 0; i < numIters; ++i) {
1248 computeResidual(R, B, A, X);
1257 beta = alpha * (c / two) * (c / two);
1258 alpha = one / (d - beta);
1259 P.update(one, Z, beta);
1261 X.update(alpha, P, one);
1268template <
class ScalarType,
class MV>
1269void Chebyshev<ScalarType, MV>::
1270 fourthKindApplyImpl(
const op_type& A,
1277 std::vector<ScalarType> betas(numIters, 1.0);
1278 if (chebyshevAlgorithm_ ==
"opt_fourth") {
1279 betas = optimalWeightsImpl<ScalarType>(numIters);
1282 const ST invEig = MT(1) / (lambdaMax * boostFactor_);
1285 Teuchos::RCP<MV> Z_ptr = makeTempMultiVector(B);
1290 Teuchos::RCP<MV> X4_ptr = makeSecondTempMultiVector(B);
1294 if (!zeroStartingSolution_) {
1296 Tpetra::deep_copy(X4, X);
1298 if (ck_.is_null()) {
1299 Teuchos::RCP<const op_type> A_op = A_;
1300 ck_ = Teuchos::rcp(
new ChebyshevKernel<op_type>(A_op, ckUseNativeSpMV_));
1304 ck_->compute(Z, MT(4.0 / 3.0) * invEig,
const_cast<V&
>(D_inv),
1305 const_cast<MV&
>(B), X4, STS::zero());
1308 X.update(betas[0], Z, STS::one());
1311 firstIterationWithZeroStartingSolution(Z, MT(4.0 / 3.0) * invEig, D_inv, B, X4);
1314 X.update(betas[0], Z, STS::zero());
1317 if (numIters > 1 && ck_.is_null()) {
1318 Teuchos::RCP<const op_type> A_op = A_;
1319 ck_ = Teuchos::rcp(
new ChebyshevKernel<op_type>(A_op, ckUseNativeSpMV_));
1322 for (
int i = 1; i < numIters; ++i) {
1323 const ST zScale = (2.0 * i - 1.0) / (2.0 * i + 3.0);
1324 const ST rScale = MT((8.0 * i + 4.0) / (2.0 * i + 3.0)) * invEig;
1328 ck_->compute(Z, rScale,
const_cast<V&
>(D_inv),
1329 const_cast<MV&
>(B), (X4), zScale);
1332 X.update(betas[i], Z, STS::one());
1336template <
class ScalarType,
class MV>
1338Chebyshev<ScalarType, MV>::maxNormInf(
const MV& X) {
1339 Teuchos::Array<MT> norms(X.getNumVectors());
1341 return *std::max_element(norms.begin(), norms.end());
1344template <
class ScalarType,
class MV>
1345void Chebyshev<ScalarType, MV>::
1346 ifpackApplyImpl(
const op_type& A,
1358 *out_ <<
" \\|B\\|_{\\infty} = " << maxNormInf(B) << endl;
1359 *out_ <<
" \\|X\\|_{\\infty} = " << maxNormInf(X) << endl;
1362 if (numIters <= 0) {
1365 const ST zero =
static_cast<ST
>(0.0);
1366 const ST one =
static_cast<ST
>(1.0);
1367 const ST two =
static_cast<ST
>(2.0);
1370 if (lambdaMin == one && lambdaMax == lambdaMin) {
1376 const ST alpha = lambdaMax / eigRatio;
1377 const ST beta = boostFactor_ * lambdaMax;
1378 const ST delta = two / (beta - alpha);
1379 const ST theta = (beta + alpha) / two;
1380 const ST s1 = theta * delta;
1383 *out_ <<
" alpha = " << alpha << endl
1384 <<
" beta = " << beta << endl
1385 <<
" delta = " << delta << endl
1386 <<
" theta = " << theta << endl
1387 <<
" s1 = " << s1 << endl;
1391 Teuchos::RCP<MV> W_ptr = makeTempMultiVector(B);
1395 *out_ <<
" Iteration " << 1 <<
":" << endl
1396 <<
" - \\|D\\|_{\\infty} = " << D_->normInf() << endl;
1400 if (!zeroStartingSolution_) {
1403 if (ck_.is_null()) {
1404 Teuchos::RCP<const op_type> A_op = A_;
1405 ck_ = Teuchos::rcp(
new ChebyshevKernel<op_type>(A_op, ckUseNativeSpMV_));
1409 ck_->compute(W, one / theta,
const_cast<V&
>(D_inv),
1410 const_cast<MV&
>(B), X, zero);
1413 firstIterationWithZeroStartingSolution(W, one / theta, D_inv, B, X);
1417 *out_ <<
" - \\|W\\|_{\\infty} = " << maxNormInf(W) << endl
1418 <<
" - \\|X\\|_{\\infty} = " << maxNormInf(X) << endl;
1421 if (numIters > 1 && ck_.is_null()) {
1422 Teuchos::RCP<const op_type> A_op = A_;
1423 ck_ = Teuchos::rcp(
new ChebyshevKernel<op_type>(A_op, ckUseNativeSpMV_));
1428 ST rhokp1, dtemp1, dtemp2;
1429 for (
int deg = 1; deg < numIters; ++deg) {
1431 *out_ <<
" Iteration " << deg + 1 <<
":" << endl
1432 <<
" - \\|D\\|_{\\infty} = " << D_->normInf() << endl
1433 <<
" - \\|B\\|_{\\infty} = " << maxNormInf(B) << endl
1434 <<
" - \\|A\\|_{\\text{frob}} = " << A_->getFrobeniusNorm()
1436 <<
" - rhok = " << rhok << endl;
1439 rhokp1 = one / (two * s1 - rhok);
1440 dtemp1 = rhokp1 * rhok;
1441 dtemp2 = two * rhokp1 * delta;
1445 *out_ <<
" - dtemp1 = " << dtemp1 << endl
1446 <<
" - dtemp2 = " << dtemp2 << endl;
1451 ck_->compute(W, dtemp2,
const_cast<V&
>(D_inv),
1452 const_cast<MV&
>(B), (X), dtemp1);
1455 *out_ <<
" - \\|W\\|_{\\infty} = " << maxNormInf(W) << endl
1456 <<
" - \\|X\\|_{\\infty} = " << maxNormInf(X) << endl;
1461template <
class ScalarType,
class MV>
1463Chebyshev<ScalarType, MV>::
1464 cgMethodWithInitGuess(
const op_type& A,
1469 using MagnitudeType =
typename STS::magnitudeType;
1471 *out_ <<
" cgMethodWithInitGuess:" << endl;
1474 const ST one = STS::one();
1475 ST beta, betaOld = one, pAp, pApOld = one, alpha, rHz, rHzOld, rHzOld2 = one, lambdaMax;
1477 Teuchos::ArrayRCP<MagnitudeType> diag, offdiag;
1478 Teuchos::RCP<V> p, z, Ap;
1479 diag.resize(numIters);
1480 offdiag.resize(numIters - 1);
1482 p = rcp(
new V(A.getRangeMap()));
1483 z = rcp(
new V(A.getRangeMap()));
1484 Ap = rcp(
new V(A.getRangeMap()));
1487 solve(*p, D_inv, r);
1490 for (
int iter = 0; iter < numIters; ++iter) {
1492 *out_ <<
" Iteration " << iter << endl;
1497 r.update(-alpha, *Ap, one);
1499 solve(*z, D_inv, r);
1501 beta = rHz / rHzOld;
1502 p->update(one, *z, beta);
1504 diag[iter] = STS::real((betaOld * betaOld * pApOld + pAp) / rHzOld);
1505 offdiag[iter - 1] = -STS::real((betaOld * pApOld / (sqrt(rHzOld * rHzOld2))));
1507 *out_ <<
" diag[" << iter <<
"] = " << diag[iter] << endl;
1508 *out_ <<
" offdiag[" << iter - 1 <<
"] = " << offdiag[iter - 1] << endl;
1509 *out_ <<
" rHz = " << rHz << endl;
1510 *out_ <<
" alpha = " << alpha << endl;
1511 *out_ <<
" beta = " << beta << endl;
1514 diag[iter] = STS::real(pAp / rHzOld);
1516 *out_ <<
" diag[" << iter <<
"] = " << diag[iter] << endl;
1517 *out_ <<
" rHz = " << rHz << endl;
1518 *out_ <<
" alpha = " << alpha << endl;
1519 *out_ <<
" beta = " << beta << endl;
1527 lambdaMax = LapackHelper<ST>::tri_diag_spectral_radius(diag, offdiag);
1532template <
class ScalarType,
class MV>
1534Chebyshev<ScalarType, MV>::
1535 cgMethod(
const op_type& A,
const V& D_inv,
const int numIters) {
1539 *out_ <<
"cgMethod:" << endl;
1543 if (eigVector_.is_null()) {
1544 r = rcp(
new V(A.getDomainMap()));
1545 if (eigKeepVectors_)
1548 Details::computeInitialGuessForCG(D_inv, *r);
1552 ST lambdaMax = cgMethodWithInitGuess(A, D_inv, numIters, *r);
1557template <
class ScalarType,
class MV>
1558Teuchos::RCP<const typename Chebyshev<ScalarType, MV>::row_matrix_type>
1563template <
class ScalarType,
class MV>
1570template <
class ScalarType,
class MV>
1578 const size_t B_numVecs = B.getNumVectors();
1579 if (W_.is_null() || W_->getNumVectors() !=
B_numVecs) {
1580 W_ = Teuchos::rcp(
new MV(B.getMap(),
B_numVecs,
false));
1585template <
class ScalarType,
class MV>
1587Chebyshev<ScalarType, MV>::
1588 makeSecondTempMultiVector(
const MV& B) {
1593 const size_t B_numVecs = B.getNumVectors();
1594 if (W2_.is_null() || W2_->getNumVectors() != B_numVecs) {
1595 W2_ = Teuchos::rcp(
new MV(B.getMap(), B_numVecs,
false));
1600template <
class ScalarType,
class MV>
1604 std::ostringstream
oss;
1607 oss <<
"\"Ifpack2::Details::Chebyshev\":"
1609 <<
"degree: " << numIters_
1610 <<
", lambdaMax: " << lambdaMaxForApply_
1611 <<
", alpha: " << eigRatioForApply_
1612 <<
", lambdaMin: " << lambdaMinForApply_
1613 <<
", boost factor: " << boostFactor_
1614 <<
", algorithm: " << chebyshevAlgorithm_;
1615 if (!userInvDiag_.is_null())
1616 oss <<
", diagonal: user-supplied";
1621template <
class ScalarType,
class MV>
1624 const Teuchos::EVerbosityLevel
verbLevel)
const {
1626 using Teuchos::TypeNameTraits;
1628 const Teuchos::EVerbosityLevel
vl =
1630 if (
vl == Teuchos::VERB_NONE) {
1646 if (A_.is_null() || A_->getComm().is_null()) {
1649 myRank = A_->getComm()->getRank();
1654 out <<
"\"Ifpack2::Details::Chebyshev\":" <<
endl;
1658 if (
vl == Teuchos::VERB_LOW) {
1660 out <<
"degree: " << numIters_ <<
endl
1661 <<
"lambdaMax: " << lambdaMaxForApply_ <<
endl
1662 <<
"alpha: " << eigRatioForApply_ <<
endl
1663 <<
"lambdaMin: " << lambdaMinForApply_ <<
endl
1664 <<
"boost factor: " << boostFactor_ <<
endl;
1672 out <<
"Template parameters:" <<
endl;
1682 out <<
"Computed parameters:" <<
endl;
1698 }
else if (
vl <= Teuchos::VERB_HIGH) {
1713 out <<
"W_: " << (W_.is_null() ?
"unset" :
"set") <<
endl
1714 <<
"computedLambdaMax_: " << computedLambdaMax_ <<
endl
1715 <<
"computedLambdaMin_: " << computedLambdaMin_ <<
endl
1716 <<
"lambdaMaxForApply_: " << lambdaMaxForApply_ <<
endl
1717 <<
"lambdaMinForApply_: " << lambdaMinForApply_ <<
endl
1718 <<
"eigRatioForApply_: " << eigRatioForApply_ <<
endl;
1723 out <<
"User parameters:" <<
endl;
1729 out <<
"userInvDiag_: ";
1730 if (userInvDiag_.is_null()) {
1732 }
else if (
vl <= Teuchos::VERB_HIGH) {
1741 out <<
"userLambdaMax_: " << userLambdaMax_ <<
endl
1742 <<
"userLambdaMin_: " << userLambdaMin_ <<
endl
1743 <<
"userEigRatio_: " << userEigRatio_ <<
endl
1744 <<
"numIters_: " << numIters_ <<
endl
1745 <<
"eigMaxIters_: " << eigMaxIters_ <<
endl
1746 <<
"eigRelTolerance_: " << eigRelTolerance_ <<
endl
1747 <<
"eigNormalizationFreq_: " << eigNormalizationFreq_ <<
endl
1748 <<
"zeroStartingSolution_: " << zeroStartingSolution_ <<
endl
1749 <<
"assumeMatrixUnchanged_: " << assumeMatrixUnchanged_ <<
endl
1750 <<
"chebyshevAlgorithm_: " << chebyshevAlgorithm_ <<
endl
1751 <<
"computeMaxResNorm_: " << computeMaxResNorm_ <<
endl;