324 , eigenAnalysisType_(
"power method")
325 , eigNormalizationFreq_(1)
326 , zeroStartingSolution_(
true)
327 , assumeMatrixUnchanged_(
false)
328 , chebyshevAlgorithm_(
"first")
329 , computeMaxResNorm_(
false)
330 , computeSpectralRadius_(
true)
331 , ckUseNativeSpMV_(MV::node_type::
is_gpu)
332 , preAllocateTempVector_(
true)
334 checkConstructorInput();
338template <
class ScalarType,
class MV>
343 using Teuchos::rcp_const_cast;
409 if (
plist.isType<
bool>(
"debug")) {
411 }
else if (
plist.isType<
int>(
"debug")) {
475 if (
plist.isParameter(
"chebyshev: use native spmv"))
479 if (
plist.isParameter(
"chebyshev: pre-allocate temp vector"))
485 if (
plist.isParameter(
"chebyshev: max eigenvalue")) {
486 if (
plist.isType<
double>(
"chebyshev: max eigenvalue"))
491 STS::isnaninf(
lambdaMax), std::invalid_argument,
492 "Ifpack2::Chebyshev::setParameters: \"chebyshev: max 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.");
496 if (
plist.isParameter(
"chebyshev: min eigenvalue")) {
497 if (
plist.isType<
double>(
"chebyshev: min eigenvalue"))
502 STS::isnaninf(
lambdaMin), std::invalid_argument,
503 "Ifpack2::Chebyshev::setParameters: \"chebyshev: min eigenvalue\" "
504 "parameter is NaN or Inf. This parameter is optional, but if you "
505 "choose to supply it, it must have a finite value.");
509 if (
plist.isParameter(
"smoother: Chebyshev alpha")) {
510 if (
plist.isType<
double>(
"smoother: Chebyshev alpha"))
518 STS::isnaninf(
eigRatio), std::invalid_argument,
519 "Ifpack2::Chebyshev::setParameters: \"chebyshev: ratio eigenvalue\" "
520 "parameter (also called \"smoother: Chebyshev alpha\") is NaN or Inf. "
521 "This parameter is optional, but if you choose to supply it, it must have "
529 STS::real(
eigRatio) < STS::real(STS::one()),
530 std::invalid_argument,
531 "Ifpack2::Chebyshev::setParameters: \"chebyshev: ratio eigenvalue\""
532 "parameter (also called \"smoother: Chebyshev alpha\") must be >= 1, "
533 "but you supplied the value "
539 const char paramName[] =
"chebyshev: boost factor";
544 }
else if (!std::is_same<double, MT>::value &&
550 "Ifpack2::Chebyshev::setParameters: \"chebyshev: boost factor\""
551 "parameter must have type magnitude_type (MT) or double.");
563 "Ifpack2::Chebyshev::setParameters: \"" <<
paramName <<
"\" parameter "
564 "must be >= 1, but you supplied the value "
571 STS::isnaninf(
minDiagVal), std::invalid_argument,
572 "Ifpack2::Chebyshev::setParameters: \"chebyshev: min diagonal value\" "
573 "parameter is NaN or Inf. This parameter is optional, but if you choose "
574 "to supply it, it must have a finite value.");
577 if (
plist.isParameter(
"smoother: sweeps")) {
580 if (
plist.isParameter(
"relaxation: sweeps")) {
585 numIters < 0, std::invalid_argument,
586 "Ifpack2::Chebyshev::setParameters: \"chebyshev: degree\" parameter (also "
587 "called \"smoother: sweeps\" or \"relaxation: sweeps\") must be a "
588 "nonnegative integer. You gave a value of "
592 if (
plist.isParameter(
"eigen-analysis: iterations")) {
598 "Ifpack2::Chebyshev::setParameters: \"chebyshev: eigenvalue max iterations"
599 "\" parameter (also called \"eigen-analysis: iterations\") must be a "
600 "nonnegative integer. You gave a value of "
603 if (
plist.isType<
double>(
"chebyshev: eigenvalue relative tolerance"))
604 eigRelTolerance = Teuchos::as<MT>(
plist.get<
double>(
"chebyshev: eigenvalue relative tolerance"));
605 else if (
plist.isType<
MT>(
"chebyshev: eigenvalue relative tolerance"))
607 else if (
plist.isType<
ST>(
"chebyshev: eigenvalue relative tolerance"))
608 eigRelTolerance = Teuchos::ScalarTraits<ST>::magnitude(
plist.get<
ST>(
"chebyshev: eigenvalue relative tolerance"));
615 "Ifpack2::Chebyshev::setParameters: \"chebyshev: eigenvalue normalization frequency"
616 "\" parameter must be a "
617 "nonnegative integer. You gave a value of "
620 zeroStartingSolution =
plist.get(
"chebyshev: zero starting solution",
621 zeroStartingSolution);
627 if (
plist.isParameter(
"chebyshev: algorithm")) {
634 std::invalid_argument,
635 "Ifpack2::Chebyshev: Ifpack2 only supports \"first\", \"textbook\", \"fourth\", and \"opt_fourth\", for \"chebyshev: algorithm\".");
638#ifdef IFPACK2_ENABLE_DEPRECATED_CODE
641 if (!
plist.isParameter(
"chebyshev: algorithm")) {
642 if (
plist.isParameter(
"chebyshev: textbook algorithm")) {
653 if (
plist.isParameter(
"chebyshev: compute max residual norm")) {
656 if (
plist.isParameter(
"chebyshev: compute spectral radius")) {
664 !
plist.get<
bool>(
"chebyshev: use block mode"),
665 std::invalid_argument,
666 "Ifpack2::Chebyshev requires that if you set \"chebyshev: use "
667 "block mode\" at all, you must set it to false. "
668 "Ifpack2::Chebyshev does not implement Ifpack's block mode.");
670 !
plist.get<
bool>(
"chebyshev: solve normal equations"),
671 std::invalid_argument,
672 "Ifpack2::Chebyshev does not and will never implement the Ifpack "
673 "parameter \"chebyshev: solve normal equations\". If you want to "
674 "solve the normal equations, construct a Tpetra::Operator that "
675 "implements A^* A, and use Chebyshev to solve A^* A x = A^* b.");
684 if (
plist.isParameter(
"eigen-analysis: type")) {
690 std::invalid_argument,
691 "Ifpack2::Chebyshev: Ifpack2 only supports \"power method\" and \"cg\" for \"eigen-analysis: type\".");
707 zeroStartingSolution_ = zeroStartingSolution;
719 if (A_.is_null() || A_->getComm().is_null()) {
724 myRank = A_->getComm()->getRank();
728 out_ = Teuchos::getFancyOStream(Teuchos::rcpFromRef(std::cerr));
730 using Teuchos::oblackholestream;
732 out_ = Teuchos::getFancyOStream(
blackHole);
736 out_ = Teuchos::null;
740template <
class ScalarType,
class MV>
744 diagOffsets_ = offsets_type();
745 savedDiagOffsets_ =
false;
747 computedLambdaMax_ = STS::nan();
748 computedLambdaMin_ = STS::nan();
749 eigVector_ = Teuchos::null;
750 eigVector2_ = Teuchos::null;
753template <
class ScalarType,
class MV>
755 setMatrix(
const Teuchos::RCP<const row_matrix_type>& A) {
756 if (A.getRawPtr() != A_.getRawPtr()) {
757 if (!assumeMatrixUnchanged_) {
769 if (A.is_null() || A->getComm().is_null()) {
774 myRank = A->getComm()->getRank();
778 out_ = Teuchos::getFancyOStream(Teuchos::rcpFromRef(std::cerr));
780 Teuchos::RCP<Teuchos::oblackholestream>
blackHole(
new Teuchos::oblackholestream());
781 out_ = Teuchos::getFancyOStream(
blackHole);
785 out_ = Teuchos::null;
790template <
class ScalarType,
class MV>
797 typedef Tpetra::CrsMatrix<
typename MV::scalar_type,
798 typename MV::local_ordinal_type,
799 typename MV::global_ordinal_type,
800 typename MV::node_type>
804 A_.is_null(), std::runtime_error,
805 "Ifpack2::Chebyshev::compute: The input "
806 "matrix A is null. Please call setMatrix() with a nonnull input matrix "
807 "before calling this method.");
822 if (userInvDiag_.is_null()) {
823 Teuchos::RCP<const crs_matrix_type>
A_crsMat =
824 Teuchos::rcp_dynamic_cast<const crs_matrix_type>(A_);
830 diagOffsets_ = offsets_type();
831 diagOffsets_ = offsets_type(
"offsets",
lclNumRows);
833 A_crsMat->getCrsGraph()->getLocalDiagOffsets(diagOffsets_);
834 savedDiagOffsets_ =
true;
835 D_ = makeInverseDiagonal(*A_,
true);
837 D_ = makeInverseDiagonal(*A_);
839 }
else if (!assumeMatrixUnchanged_) {
843 if (!savedDiagOffsets_) {
846 diagOffsets_ = offsets_type();
847 diagOffsets_ = offsets_type(
"offsets",
lclNumRows);
849 A_crsMat->getCrsGraph()->getLocalDiagOffsets(diagOffsets_);
850 savedDiagOffsets_ =
true;
853 D_ = makeInverseDiagonal(*A_,
true);
855 D_ = makeInverseDiagonal(*A_);
859 D_ = makeRangeMapVectorConst(userInvDiag_);
864 STS::isnaninf(computedLambdaMax_) || STS::isnaninf(computedLambdaMin_);
874 if (!assumeMatrixUnchanged_ ||
877 if ((eigenAnalysisType_ ==
"power method") || (eigenAnalysisType_ ==
"power-method")) {
879 if (eigVector_.is_null()) {
880 x = Teuchos::rcp(
new V(A_->getDomainMap()));
883 PowerMethod::computeInitialGuessForPowerMethod(*x,
false);
888 if (eigVector2_.is_null()) {
889 y =
rcp(
new V(A_->getRangeMap()));
895 Teuchos::RCP<Teuchos::FancyOStream> stream = (debug_ ? out_ : Teuchos::null);
896 computedLambdaMax = PowerMethod::powerMethodWithInitGuess(*A_, *D_, eigMaxIters_, x, y,
897 eigRelTolerance_, eigNormalizationFreq_, stream,
898 computeSpectralRadius_);
905 "Ifpack2::Chebyshev::compute: Estimation of the max eigenvalue "
906 "of D^{-1} A failed, by producing Inf or NaN. This probably means that "
907 "the matrix contains Inf or NaN values, or that it is badly scaled.");
909 STS::isnaninf(userEigRatio_),
911 "Ifpack2::Chebyshev::compute: userEigRatio_ is Inf or NaN."
913 <<
"This should be impossible." <<
endl
914 <<
"Please report this bug to the Ifpack2 developers.");
927 STS::isnaninf(userLambdaMax_) && STS::isnaninf(computedLambdaMax_),
929 "Ifpack2::Chebyshev::compute: " <<
endl
930 <<
"Both userLambdaMax_ and computedLambdaMax_ are Inf or NaN."
932 <<
"This should be impossible." <<
endl
933 <<
"Please report this bug to the Ifpack2 developers.");
941 lambdaMaxForApply_ = STS::isnaninf(userLambdaMax_) ? computedLambdaMax_ : userLambdaMax_;
954 lambdaMinForApply_ = lambdaMaxForApply_ / userEigRatio_;
955 eigRatioForApply_ = userEigRatio_;
957 if (chebyshevAlgorithm_ ==
"first") {
960 const ST one = Teuchos::as<ST>(1);
963 if (STS::magnitude(lambdaMaxForApply_ -
one) < Teuchos::as<MT>(1.0e-6)) {
964 lambdaMinForApply_ =
one;
965 lambdaMaxForApply_ = lambdaMinForApply_;
966 eigRatioForApply_ =
one;
971 if (preAllocateTempVector_ && !D_.is_null()) {
972 makeTempMultiVector(*D_);
973 if (chebyshevAlgorithm_ ==
"fourth" || chebyshevAlgorithm_ ==
"opt_fourth") {
974 makeSecondTempMultiVector(*D_);
978 if (chebyshevAlgorithm_ ==
"textbook") {
984 if (ckUseNativeSpMV_) {
985 ck_->setAuxiliaryVectors(1);
990template <
class ScalarType,
class MV>
994 return lambdaMaxForApply_;
997template <
class ScalarType,
class MV>
1000 const char prefix[] =
"Ifpack2::Chebyshev::apply: ";
1003 *out_ <<
"apply: " << std::endl;
1006 " Please call setMatrix() with a nonnull input matrix, and then call "
1007 "compute(), before calling this method.");
1009 prefix <<
"There is no estimate for the max eigenvalue."
1013 prefix <<
"There is no estimate for the min eigenvalue."
1017 prefix <<
"There is no estimate for the ratio of the max "
1018 "eigenvalue to the min eigenvalue."
1022 "diagonal entries of the matrix has not yet been computed."
1026 if (chebyshevAlgorithm_ ==
"fourth" || chebyshevAlgorithm_ ==
"opt_fourth") {
1027 fourthKindApplyImpl(*A_, B, X, numIters_, lambdaMaxForApply_, *D_);
1028 }
else if (chebyshevAlgorithm_ ==
"textbook") {
1029 textbookApplyImpl(*A_, B, X, numIters_, lambdaMaxForApply_,
1030 lambdaMinForApply_, eigRatioForApply_, *D_);
1032 ifpackApplyImpl(*A_, B, X, numIters_, lambdaMaxForApply_,
1033 lambdaMinForApply_, eigRatioForApply_, *D_);
1036 if (computeMaxResNorm_ && B.getNumVectors() > 0) {
1037 MV R(B.getMap(), B.getNumVectors());
1038 computeResidual(R, B, *A_, X);
1039 Teuchos::Array<MT>
norms(B.getNumVectors());
1041 return *std::max_element(
norms.begin(),
norms.end());
1043 return Teuchos::ScalarTraits<MT>::zero();
1047template <
class ScalarType,
class MV>
1050 using Teuchos::rcpFromRef;
1052 Teuchos::VERB_MEDIUM);
1055template <
class ScalarType,
class MV>
1063 Tpetra::deep_copy(X, W);
1066template <
class ScalarType,
class MV>
1069 const Teuchos::ETransp mode) {
1070 Tpetra::Details::residual(A, X, B, R);
1073template <
class ScalarType,
class MV>
1074void Chebyshev<ScalarType, MV>::
1075 solve(MV& Z,
const V& D_inv,
const MV& R) {
1076 Z.elementWiseMultiply(STS::one(), D_inv, R, STS::zero());
1079template <
class ScalarType,
class MV>
1080void Chebyshev<ScalarType, MV>::
1081 solve(MV& Z,
const ST alpha,
const V& D_inv,
const MV& R) {
1082 Z.elementWiseMultiply(alpha, D_inv, R, STS::zero());
1085template <
class ScalarType,
class MV>
1086Teuchos::RCP<const typename Chebyshev<ScalarType, MV>::V>
1087Chebyshev<ScalarType, MV>::
1088 makeInverseDiagonal(
const row_matrix_type& A,
const bool useDiagOffsets)
const {
1090 using Teuchos::rcp_dynamic_cast;
1091 using Teuchos::rcpFromRef;
1094 if (!D_.is_null() &&
1095 D_->getMap()->isSameAs(*(A.getRowMap()))) {
1097 *out_ <<
"Reusing pre-existing vector for diagonal extraction" << std::endl;
1098 D_rowMap = Teuchos::rcp_const_cast<V>(D_);
1100 D_rowMap = Teuchos::rcp(
new V(A.getRowMap(),
false));
1102 *out_ <<
"Allocated new vector for diagonal extraction" << std::endl;
1104 if (useDiagOffsets) {
1108 typedef Tpetra::CrsMatrix<
typename MV::scalar_type,
1109 typename MV::local_ordinal_type,
1110 typename MV::global_ordinal_type,
1111 typename MV::node_type>
1113 RCP<const crs_matrix_type> A_crsMat =
1114 rcp_dynamic_cast<const crs_matrix_type>(rcpFromRef(A));
1115 if (!A_crsMat.is_null()) {
1116 TEUCHOS_TEST_FOR_EXCEPTION(
1117 !savedDiagOffsets_, std::logic_error,
1118 "Ifpack2::Details::Chebyshev::makeInverseDiagonal: "
1119 "It is not allowed to call this method with useDiagOffsets=true, "
1120 "if you have not previously saved offsets of diagonal entries. "
1121 "This situation should never arise if this class is used properly. "
1122 "Please report this bug to the Ifpack2 developers.");
1123 A_crsMat->getLocalDiagCopy(*D_rowMap, diagOffsets_);
1128 A.getLocalDiagCopy(*D_rowMap);
1130 RCP<V> D_rangeMap = makeRangeMapVector(D_rowMap);
1136 bool foundNonpositiveValue =
false;
1138 auto D_lcl = D_rangeMap->getLocalViewHost(Tpetra::Access::ReadOnly);
1139 auto D_lcl_1d = Kokkos::subview(D_lcl, Kokkos::ALL(), 0);
1141 typedef typename MV::impl_scalar_type IST;
1142 typedef typename MV::local_ordinal_type LO;
1143#if KOKKOS_VERSION >= 40799
1144 typedef KokkosKernels::ArithTraits<IST> ATS;
1146 typedef Kokkos::ArithTraits<IST> ATS;
1148#if KOKKOS_VERSION >= 40799
1149 typedef KokkosKernels::ArithTraits<typename ATS::mag_type> STM;
1151 typedef Kokkos::ArithTraits<typename ATS::mag_type> STM;
1154 const LO lclNumRows =
static_cast<LO
>(D_rangeMap->getLocalLength());
1155 for (LO i = 0; i < lclNumRows; ++i) {
1156 if (STS::real(D_lcl_1d(i)) <= STM::zero()) {
1157 foundNonpositiveValue =
true;
1163 using Teuchos::outArg;
1164 using Teuchos::REDUCE_MIN;
1165 using Teuchos::reduceAll;
1167 const int lclSuccess = foundNonpositiveValue ? 0 : 1;
1168 int gblSuccess = lclSuccess;
1169 if (!D_rangeMap->getMap().is_null() && D_rangeMap->getMap()->getComm().is_null()) {
1170 const Teuchos::Comm<int>& comm = *(D_rangeMap->getMap()->getComm());
1171 reduceAll<int, int>(comm, REDUCE_MIN, lclSuccess, outArg(gblSuccess));
1173 if (gblSuccess == 1) {
1174 *out_ <<
"makeInverseDiagonal: The matrix's diagonal entries all have "
1175 "positive real part (this is good for Chebyshev)."
1178 *out_ <<
"makeInverseDiagonal: The matrix's diagonal has at least one "
1179 "entry with nonpositive real part, on at least one process in the "
1180 "matrix's communicator. This is bad for Chebyshev."
1187 reciprocal_threshold(*D_rangeMap, minDiagVal_);
1188 return Teuchos::rcp_const_cast<const V>(D_rangeMap);
1191template <
class ScalarType,
class MV>
1192Teuchos::RCP<const typename Chebyshev<ScalarType, MV>::V>
1193Chebyshev<ScalarType, MV>::
1194 makeRangeMapVectorConst(
const Teuchos::RCP<const V>& D)
const {
1197 typedef Tpetra::Export<
typename MV::local_ordinal_type,
1198 typename MV::global_ordinal_type,
1199 typename MV::node_type>
1204 TEUCHOS_TEST_FOR_EXCEPTION(
1205 A_.is_null(), std::logic_error,
1206 "Ifpack2::Details::Chebyshev::"
1207 "makeRangeMapVector: The input matrix A is null. Please call setMatrix() "
1208 "with a nonnull input matrix before calling this method. This is probably "
1209 "a bug in Ifpack2; please report this bug to the Ifpack2 developers.");
1210 TEUCHOS_TEST_FOR_EXCEPTION(
1211 D.is_null(), std::logic_error,
1212 "Ifpack2::Details::Chebyshev::"
1213 "makeRangeMapVector: The input Vector D is null. This is probably "
1214 "a bug in Ifpack2; please report this bug to the Ifpack2 developers.");
1216 RCP<const map_type> sourceMap = D->getMap();
1217 RCP<const map_type> rangeMap = A_->getRangeMap();
1218 RCP<const map_type> rowMap = A_->getRowMap();
1220 if (rangeMap->isSameAs(*sourceMap)) {
1225 RCP<const export_type> exporter;
1229 if (sourceMap->isSameAs(*rowMap)) {
1231 exporter = A_->getGraph()->getExporter();
1233 exporter = rcp(
new export_type(sourceMap, rangeMap));
1236 if (exporter.is_null()) {
1239 RCP<V> D_out = rcp(
new V(*D, Teuchos::Copy));
1240 D_out->doExport(*D, *exporter, Tpetra::ADD);
1241 return Teuchos::rcp_const_cast<const V>(D_out);
1246template <
class ScalarType,
class MV>
1247Teuchos::RCP<typename Chebyshev<ScalarType, MV>::V>
1248Chebyshev<ScalarType, MV>::
1249 makeRangeMapVector(
const Teuchos::RCP<V>& D)
const {
1250 using Teuchos::rcp_const_cast;
1251 return rcp_const_cast<V>(makeRangeMapVectorConst(rcp_const_cast<V>(D)));
1254template <
class ScalarType,
class MV>
1255void Chebyshev<ScalarType, MV>::
1256 textbookApplyImpl(
const op_type& A,
1263 const V& D_inv)
const {
1265 const ST myLambdaMin = lambdaMax / eigRatio;
1267 const ST zero = Teuchos::as<ST>(0);
1268 const ST one = Teuchos::as<ST>(1);
1269 const ST two = Teuchos::as<ST>(2);
1270 const ST d = (lambdaMax + myLambdaMin) / two;
1271 const ST c = (lambdaMax - myLambdaMin) / two;
1273 if (zeroStartingSolution_ && numIters > 0) {
1277 MV R(B.getMap(), B.getNumVectors(),
false);
1278 MV P(B.getMap(), B.getNumVectors(),
false);
1279 MV Z(B.getMap(), B.getNumVectors(),
false);
1281 for (
int i = 0; i < numIters; ++i) {
1282 computeResidual(R, B, A, X);
1291 beta = alpha * (c / two) * (c / two);
1292 alpha = one / (d - beta);
1293 P.update(one, Z, beta);
1295 X.update(alpha, P, one);
1302template <
class ScalarType,
class MV>
1303void Chebyshev<ScalarType, MV>::
1304 fourthKindApplyImpl(
const op_type& A,
1311 std::vector<ScalarType> betas(numIters, 1.0);
1312 if (chebyshevAlgorithm_ ==
"opt_fourth") {
1313 betas = optimalWeightsImpl<ScalarType>(numIters);
1316 const ST invEig = MT(1) / (lambdaMax * boostFactor_);
1319 Teuchos::RCP<MV> Z_ptr = makeTempMultiVector(B);
1324 Teuchos::RCP<MV> X4_ptr = makeSecondTempMultiVector(B);
1328 if (!zeroStartingSolution_) {
1330 Tpetra::deep_copy(X4, X);
1332 if (ck_.is_null()) {
1333 Teuchos::RCP<const op_type> A_op = A_;
1334 ck_ = Teuchos::rcp(
new ChebyshevKernel<op_type>(A_op, ckUseNativeSpMV_));
1338 ck_->compute(Z, MT(4.0 / 3.0) * invEig,
const_cast<V&
>(D_inv),
1339 const_cast<MV&
>(B), X4, STS::zero());
1342 X.update(betas[0], Z, STS::one());
1345 firstIterationWithZeroStartingSolution(Z, MT(4.0 / 3.0) * invEig, D_inv, B, X4);
1348 X.update(betas[0], Z, STS::zero());
1351 if (numIters > 1 && ck_.is_null()) {
1352 Teuchos::RCP<const op_type> A_op = A_;
1353 ck_ = Teuchos::rcp(
new ChebyshevKernel<op_type>(A_op, ckUseNativeSpMV_));
1356 for (
int i = 1; i < numIters; ++i) {
1357 const ST zScale = (2.0 * i - 1.0) / (2.0 * i + 3.0);
1358 const ST rScale = MT((8.0 * i + 4.0) / (2.0 * i + 3.0)) * invEig;
1362 ck_->compute(Z, rScale,
const_cast<V&
>(D_inv),
1363 const_cast<MV&
>(B), (X4), zScale);
1366 X.update(betas[i], Z, STS::one());
1370template <
class ScalarType,
class MV>
1372Chebyshev<ScalarType, MV>::maxNormInf(
const MV& X) {
1373 Teuchos::Array<MT> norms(X.getNumVectors());
1375 return *std::max_element(norms.begin(), norms.end());
1378template <
class ScalarType,
class MV>
1379void Chebyshev<ScalarType, MV>::
1380 ifpackApplyImpl(
const op_type& A,
1389#ifdef HAVE_IFPACK2_DEBUG
1390 const bool debug = debug_;
1392 const bool debug =
false;
1396 *out_ <<
" \\|B\\|_{\\infty} = " << maxNormInf(B) << endl;
1397 *out_ <<
" \\|X\\|_{\\infty} = " << maxNormInf(X) << endl;
1400 if (numIters <= 0) {
1403 const ST zero =
static_cast<ST
>(0.0);
1404 const ST one =
static_cast<ST
>(1.0);
1405 const ST two =
static_cast<ST
>(2.0);
1408 if (lambdaMin == one && lambdaMax == lambdaMin) {
1414 const ST alpha = lambdaMax / eigRatio;
1415 const ST beta = boostFactor_ * lambdaMax;
1416 const ST delta = two / (beta - alpha);
1417 const ST theta = (beta + alpha) / two;
1418 const ST s1 = theta * delta;
1421 *out_ <<
" alpha = " << alpha << endl
1422 <<
" beta = " << beta << endl
1423 <<
" delta = " << delta << endl
1424 <<
" theta = " << theta << endl
1425 <<
" s1 = " << s1 << endl;
1429 Teuchos::RCP<MV> W_ptr = makeTempMultiVector(B);
1433 *out_ <<
" Iteration " << 1 <<
":" << endl
1434 <<
" - \\|D\\|_{\\infty} = " << D_->normInf() << endl;
1438 if (!zeroStartingSolution_) {
1441 if (ck_.is_null()) {
1442 Teuchos::RCP<const op_type> A_op = A_;
1443 ck_ = Teuchos::rcp(
new ChebyshevKernel<op_type>(A_op, ckUseNativeSpMV_));
1447 ck_->compute(W, one / theta,
const_cast<V&
>(D_inv),
1448 const_cast<MV&
>(B), X, zero);
1451 firstIterationWithZeroStartingSolution(W, one / theta, D_inv, B, X);
1455 *out_ <<
" - \\|W\\|_{\\infty} = " << maxNormInf(W) << endl
1456 <<
" - \\|X\\|_{\\infty} = " << maxNormInf(X) << endl;
1459 if (numIters > 1 && ck_.is_null()) {
1460 Teuchos::RCP<const op_type> A_op = A_;
1461 ck_ = Teuchos::rcp(
new ChebyshevKernel<op_type>(A_op, ckUseNativeSpMV_));
1466 ST rhokp1, dtemp1, dtemp2;
1467 for (
int deg = 1; deg < numIters; ++deg) {
1469 *out_ <<
" Iteration " << deg + 1 <<
":" << endl
1470 <<
" - \\|D\\|_{\\infty} = " << D_->normInf() << endl
1471 <<
" - \\|B\\|_{\\infty} = " << maxNormInf(B) << endl
1472 <<
" - \\|A\\|_{\\text{frob}} = " << A_->getFrobeniusNorm()
1474 <<
" - rhok = " << rhok << endl;
1477 rhokp1 = one / (two * s1 - rhok);
1478 dtemp1 = rhokp1 * rhok;
1479 dtemp2 = two * rhokp1 * delta;
1483 *out_ <<
" - dtemp1 = " << dtemp1 << endl
1484 <<
" - dtemp2 = " << dtemp2 << endl;
1489 ck_->compute(W, dtemp2,
const_cast<V&
>(D_inv),
1490 const_cast<MV&
>(B), (X), dtemp1);
1493 *out_ <<
" - \\|W\\|_{\\infty} = " << maxNormInf(W) << endl
1494 <<
" - \\|X\\|_{\\infty} = " << maxNormInf(X) << endl;
1499template <
class ScalarType,
class MV>
1501Chebyshev<ScalarType, MV>::
1502 cgMethodWithInitGuess(
const op_type& A,
1507 using MagnitudeType =
typename STS::magnitudeType;
1509 *out_ <<
" cgMethodWithInitGuess:" << endl;
1512 const ST one = STS::one();
1513 ST beta, betaOld = one, pAp, pApOld = one, alpha, rHz, rHzOld, rHzOld2 = one, lambdaMax;
1515 Teuchos::ArrayRCP<MagnitudeType> diag, offdiag;
1516 Teuchos::RCP<V> p, z, Ap;
1517 diag.resize(numIters);
1518 offdiag.resize(numIters - 1);
1520 p = rcp(
new V(A.getRangeMap()));
1521 z = rcp(
new V(A.getRangeMap()));
1522 Ap = rcp(
new V(A.getRangeMap()));
1525 solve(*p, D_inv, r);
1528 for (
int iter = 0; iter < numIters; ++iter) {
1530 *out_ <<
" Iteration " << iter << endl;
1535 r.update(-alpha, *Ap, one);
1537 solve(*z, D_inv, r);
1539 beta = rHz / rHzOld;
1540 p->update(one, *z, beta);
1542 diag[iter] = STS::real((betaOld * betaOld * pApOld + pAp) / rHzOld);
1543 offdiag[iter - 1] = -STS::real((betaOld * pApOld / (sqrt(rHzOld * rHzOld2))));
1545 *out_ <<
" diag[" << iter <<
"] = " << diag[iter] << endl;
1546 *out_ <<
" offdiag[" << iter - 1 <<
"] = " << offdiag[iter - 1] << endl;
1547 *out_ <<
" rHz = " << rHz << endl;
1548 *out_ <<
" alpha = " << alpha << endl;
1549 *out_ <<
" beta = " << beta << endl;
1552 diag[iter] = STS::real(pAp / rHzOld);
1554 *out_ <<
" diag[" << iter <<
"] = " << diag[iter] << endl;
1555 *out_ <<
" rHz = " << rHz << endl;
1556 *out_ <<
" alpha = " << alpha << endl;
1557 *out_ <<
" beta = " << beta << endl;
1565 lambdaMax = LapackHelper<ST>::tri_diag_spectral_radius(diag, offdiag);
1570template <
class ScalarType,
class MV>
1572Chebyshev<ScalarType, MV>::
1573 cgMethod(
const op_type& A,
const V& D_inv,
const int numIters) {
1577 *out_ <<
"cgMethod:" << endl;
1581 if (eigVector_.is_null()) {
1582 r = rcp(
new V(A.getDomainMap()));
1583 if (eigKeepVectors_)
1586 Details::computeInitialGuessForCG(D_inv, *r);
1590 ST lambdaMax = cgMethodWithInitGuess(A, D_inv, numIters, *r);
1595template <
class ScalarType,
class MV>
1596Teuchos::RCP<const typename Chebyshev<ScalarType, MV>::row_matrix_type>
1601template <
class ScalarType,
class MV>
1608template <
class ScalarType,
class MV>
1616 const size_t B_numVecs = B.getNumVectors();
1617 if (W_.is_null() || W_->getNumVectors() !=
B_numVecs) {
1618 W_ = Teuchos::rcp(
new MV(B.getMap(),
B_numVecs,
false));
1623template <
class ScalarType,
class MV>
1625Chebyshev<ScalarType, MV>::
1626 makeSecondTempMultiVector(
const MV& B) {
1631 const size_t B_numVecs = B.getNumVectors();
1632 if (W2_.is_null() || W2_->getNumVectors() != B_numVecs) {
1633 W2_ = Teuchos::rcp(
new MV(B.getMap(), B_numVecs,
false));
1638template <
class ScalarType,
class MV>
1642 std::ostringstream
oss;
1645 oss <<
"\"Ifpack2::Details::Chebyshev\":"
1647 <<
"degree: " << numIters_
1648 <<
", lambdaMax: " << lambdaMaxForApply_
1649 <<
", alpha: " << eigRatioForApply_
1650 <<
", lambdaMin: " << lambdaMinForApply_
1651 <<
", boost factor: " << boostFactor_
1652 <<
", algorithm: " << chebyshevAlgorithm_;
1653 if (!userInvDiag_.is_null())
1654 oss <<
", diagonal: user-supplied";
1659template <
class ScalarType,
class MV>
1662 const Teuchos::EVerbosityLevel
verbLevel)
const {
1664 using Teuchos::TypeNameTraits;
1666 const Teuchos::EVerbosityLevel
vl =
1668 if (
vl == Teuchos::VERB_NONE) {
1684 if (A_.is_null() || A_->getComm().is_null()) {
1687 myRank = A_->getComm()->getRank();
1692 out <<
"\"Ifpack2::Details::Chebyshev\":" <<
endl;
1696 if (
vl == Teuchos::VERB_LOW) {
1698 out <<
"degree: " << numIters_ <<
endl
1699 <<
"lambdaMax: " << lambdaMaxForApply_ <<
endl
1700 <<
"alpha: " << eigRatioForApply_ <<
endl
1701 <<
"lambdaMin: " << lambdaMinForApply_ <<
endl
1702 <<
"boost factor: " << boostFactor_ <<
endl;
1710 out <<
"Template parameters:" <<
endl;
1720 out <<
"Computed parameters:" <<
endl;
1736 }
else if (
vl <= Teuchos::VERB_HIGH) {
1751 out <<
"W_: " << (W_.is_null() ?
"unset" :
"set") <<
endl
1752 <<
"computedLambdaMax_: " << computedLambdaMax_ <<
endl
1753 <<
"computedLambdaMin_: " << computedLambdaMin_ <<
endl
1754 <<
"lambdaMaxForApply_: " << lambdaMaxForApply_ <<
endl
1755 <<
"lambdaMinForApply_: " << lambdaMinForApply_ <<
endl
1756 <<
"eigRatioForApply_: " << eigRatioForApply_ <<
endl;
1761 out <<
"User parameters:" <<
endl;
1767 out <<
"userInvDiag_: ";
1768 if (userInvDiag_.is_null()) {
1770 }
else if (
vl <= Teuchos::VERB_HIGH) {
1779 out <<
"userLambdaMax_: " << userLambdaMax_ <<
endl
1780 <<
"userLambdaMin_: " << userLambdaMin_ <<
endl
1781 <<
"userEigRatio_: " << userEigRatio_ <<
endl
1782 <<
"numIters_: " << numIters_ <<
endl
1783 <<
"eigMaxIters_: " << eigMaxIters_ <<
endl
1784 <<
"eigRelTolerance_: " << eigRelTolerance_ <<
endl
1785 <<
"eigNormalizationFreq_: " << eigNormalizationFreq_ <<
endl
1786 <<
"zeroStartingSolution_: " << zeroStartingSolution_ <<
endl
1787 <<
"assumeMatrixUnchanged_: " << assumeMatrixUnchanged_ <<
endl
1788 <<
"chebyshevAlgorithm_: " << chebyshevAlgorithm_ <<
endl
1789 <<
"computeMaxResNorm_: " << computeMaxResNorm_ <<
endl;