320 lambdaMaxForApply_ (
STS::
nan ()),
322 lambdaMinForApply_ (
STS::
nan ()),
323 eigRatioForApply_ (
STS::
nan ()),
324 userLambdaMax_ (
STS::
nan ()),
325 userLambdaMin_ (
STS::
nan ()),
326 userEigRatio_ (Teuchos::
as<
ST> (30)),
327 minDiagVal_ (
STS::
eps ()),
331 eigKeepVectors_(
false),
332 eigenAnalysisType_(
"power method"),
333 eigNormalizationFreq_(1),
334 zeroStartingSolution_ (
true),
335 assumeMatrixUnchanged_ (
false),
336 chebyshevAlgorithm_(
"first"),
337 computeMaxResNorm_ (
false),
338 computeSpectralRadius_(
true),
339 ckUseNativeSpMV_(
false),
342 checkConstructorInput ();
346template<
class ScalarType,
class MV>
353 using Teuchos::rcp_const_cast;
417 if (
plist.isType<
bool> (
"debug")) {
420 else if (
plist.isType<
int> (
"debug")) {
489 if (
plist.isParameter (
"chebyshev: use native spmv"))
495 if (
plist.isParameter (
"chebyshev: max eigenvalue")) {
496 if (
plist.isType<
double>(
"chebyshev: max eigenvalue"))
501 STS::isnaninf (
lambdaMax), std::invalid_argument,
502 "Ifpack2::Chebyshev::setParameters: \"chebyshev: max eigenvalue\" "
503 "parameter is NaN or Inf. This parameter is optional, but if you "
504 "choose to supply it, it must have a finite value.");
506 if (
plist.isParameter (
"chebyshev: min eigenvalue")) {
507 if (
plist.isType<
double>(
"chebyshev: min eigenvalue"))
512 STS::isnaninf (
lambdaMin), std::invalid_argument,
513 "Ifpack2::Chebyshev::setParameters: \"chebyshev: min eigenvalue\" "
514 "parameter is NaN or Inf. This parameter is optional, but if you "
515 "choose to supply it, it must have a finite value.");
519 if (
plist.isParameter (
"smoother: Chebyshev alpha")) {
520 if (
plist.isType<
double>(
"smoother: Chebyshev alpha"))
528 STS::isnaninf (
eigRatio), std::invalid_argument,
529 "Ifpack2::Chebyshev::setParameters: \"chebyshev: ratio eigenvalue\" "
530 "parameter (also called \"smoother: Chebyshev alpha\") is NaN or Inf. "
531 "This parameter is optional, but if you choose to supply it, it must have "
539 STS::real (
eigRatio) < STS::real (STS::one ()),
540 std::invalid_argument,
541 "Ifpack2::Chebyshev::setParameters: \"chebyshev: ratio eigenvalue\""
542 "parameter (also called \"smoother: Chebyshev alpha\") must be >= 1, "
543 "but you supplied the value " <<
eigRatio <<
".");
548 const char paramName[] =
"chebyshev: boost factor";
554 else if (! std::is_same<double, MT>::value &&
561 (
true, std::invalid_argument,
562 "Ifpack2::Chebyshev::setParameters: \"chebyshev: boost factor\""
563 "parameter must have type magnitude_type (MT) or double.");
576 (
boostFactor < Teuchos::ScalarTraits<MT>::one (), std::invalid_argument,
577 "Ifpack2::Chebyshev::setParameters: \"" <<
paramName <<
"\" parameter "
578 "must be >= 1, but you supplied the value " <<
boostFactor <<
".");
584 STS::isnaninf (
minDiagVal), std::invalid_argument,
585 "Ifpack2::Chebyshev::setParameters: \"chebyshev: min diagonal value\" "
586 "parameter is NaN or Inf. This parameter is optional, but if you choose "
587 "to supply it, it must have a finite value.");
590 if (
plist.isParameter (
"smoother: sweeps")) {
593 if (
plist.isParameter (
"relaxation: sweeps")) {
598 numIters < 0, std::invalid_argument,
599 "Ifpack2::Chebyshev::setParameters: \"chebyshev: degree\" parameter (also "
600 "called \"smoother: sweeps\" or \"relaxation: sweeps\") must be a "
601 "nonnegative integer. You gave a value of " <<
numIters <<
".");
604 if (
plist.isParameter (
"eigen-analysis: iterations")) {
610 "Ifpack2::Chebyshev::setParameters: \"chebyshev: eigenvalue max iterations"
611 "\" parameter (also called \"eigen-analysis: iterations\") must be a "
612 "nonnegative integer. You gave a value of " <<
eigMaxIters <<
".");
614 if (
plist.isType<
double>(
"chebyshev: eigenvalue relative tolerance"))
615 eigRelTolerance = Teuchos::as<MT>(
plist.get<
double> (
"chebyshev: eigenvalue relative tolerance"));
616 else if (
plist.isType<
MT>(
"chebyshev: eigenvalue relative tolerance"))
618 else if (
plist.isType<
ST>(
"chebyshev: eigenvalue relative tolerance"))
619 eigRelTolerance = Teuchos::ScalarTraits<ST>::magnitude(
plist.get<
ST> (
"chebyshev: eigenvalue relative tolerance"));
626 "Ifpack2::Chebyshev::setParameters: \"chebyshev: eigenvalue normalization frequency"
627 "\" parameter must be a "
630 zeroStartingSolution =
plist.get (
"chebyshev: zero starting solution",
631 zeroStartingSolution);
637 if (
plist.isParameter (
"chebyshev: algorithm")) {
644 std::invalid_argument,
645 "Ifpack2::Chebyshev: Ifpack2 only supports \"first\", \"textbook\", \"fourth\", and \"opt_fourth\", for \"chebyshev: algorithm\".");
648#ifdef IFPACK2_ENABLE_DEPRECATED_CODE
651 if (!
plist.isParameter (
"chebyshev: algorithm")) {
652 if (
plist.isParameter (
"chebyshev: textbook algorithm")) {
663 if (
plist.isParameter (
"chebyshev: compute max residual norm")) {
666 if (
plist.isParameter (
"chebyshev: compute spectral radius")) {
676 (
plist.isType<
bool> (
"chebyshev: use block mode") &&
677 !
plist.get<
bool> (
"chebyshev: use block mode"),
678 std::invalid_argument,
679 "Ifpack2::Chebyshev requires that if you set \"chebyshev: use "
680 "block mode\" at all, you must set it to false. "
681 "Ifpack2::Chebyshev does not implement Ifpack's block mode.");
683 (
plist.isType<
bool> (
"chebyshev: solve normal equations") &&
684 !
plist.get<
bool> (
"chebyshev: solve normal equations"),
685 std::invalid_argument,
686 "Ifpack2::Chebyshev does not and will never implement the Ifpack "
687 "parameter \"chebyshev: solve normal equations\". If you want to "
688 "solve the normal equations, construct a Tpetra::Operator that "
689 "implements A^* A, and use Chebyshev to solve A^* A x = A^* b.");
698 if (
plist.isParameter (
"eigen-analysis: type")) {
704 std::invalid_argument,
705 "Ifpack2::Chebyshev: Ifpack2 only supports \"power method\" and \"cg\" for \"eigen-analysis: type\".");
721 zeroStartingSolution_ = zeroStartingSolution;
732 if (A_.is_null () || A_->getComm ().is_null ()) {
738 myRank = A_->getComm ()->getRank ();
742 out_ = Teuchos::getFancyOStream (Teuchos::rcpFromRef (std::cerr));
745 using Teuchos::oblackholestream;
747 out_ = Teuchos::getFancyOStream (
blackHole);
752 out_ = Teuchos::null;
757template<
class ScalarType,
class MV>
763 diagOffsets_ = offsets_type ();
764 savedDiagOffsets_ =
false;
766 computedLambdaMax_ = STS::nan ();
767 computedLambdaMin_ = STS::nan ();
768 eigVector_ = Teuchos::null;
769 eigVector2_ = Teuchos::null;
773template<
class ScalarType,
class MV>
776setMatrix (
const Teuchos::RCP<const row_matrix_type>& A)
778 if (A.getRawPtr () != A_.getRawPtr ()) {
779 if (! assumeMatrixUnchanged_) {
791 if (A.is_null () || A->getComm ().is_null ()) {
797 myRank = A->getComm ()->getRank ();
801 out_ = Teuchos::getFancyOStream (Teuchos::rcpFromRef (std::cerr));
804 Teuchos::RCP<Teuchos::oblackholestream>
blackHole (
new Teuchos::oblackholestream ());
805 out_ = Teuchos::getFancyOStream (
blackHole);
810 out_ = Teuchos::null;
815template<
class ScalarType,
class MV>
824 typedef Tpetra::CrsMatrix<
typename MV::scalar_type,
825 typename MV::local_ordinal_type,
826 typename MV::global_ordinal_type,
827 typename MV::node_type> crs_matrix_type;
830 A_.is_null (), std::runtime_error,
"Ifpack2::Chebyshev::compute: The input "
831 "matrix A is null. Please call setMatrix() with a nonnull input matrix "
832 "before calling this method.");
847 if (userInvDiag_.is_null ()) {
848 Teuchos::RCP<const crs_matrix_type>
A_crsMat =
849 Teuchos::rcp_dynamic_cast<const crs_matrix_type> (A_);
855 diagOffsets_ = offsets_type ();
856 diagOffsets_ = offsets_type (
"offsets",
lclNumRows);
858 A_crsMat->getCrsGraph ()->getLocalDiagOffsets (diagOffsets_);
859 savedDiagOffsets_ =
true;
860 D_ = makeInverseDiagonal (*A_,
true);
863 D_ = makeInverseDiagonal (*A_);
866 else if (! assumeMatrixUnchanged_) {
870 if (! savedDiagOffsets_) {
873 diagOffsets_ = offsets_type ();
874 diagOffsets_ = offsets_type (
"offsets",
lclNumRows);
876 A_crsMat->getCrsGraph ()->getLocalDiagOffsets (diagOffsets_);
877 savedDiagOffsets_ =
true;
880 D_ = makeInverseDiagonal (*A_,
true);
883 D_ = makeInverseDiagonal (*A_);
888 D_ = makeRangeMapVectorConst (userInvDiag_);
893 STS::isnaninf (computedLambdaMax_) || STS::isnaninf (computedLambdaMin_);
903 if (! assumeMatrixUnchanged_ ||
906 if ((eigenAnalysisType_ ==
"power method") || (eigenAnalysisType_ ==
"power-method")) {
908 if (eigVector_.is_null()) {
909 x = Teuchos::rcp(
new V(A_->getDomainMap ()));
912 PowerMethod::computeInitialGuessForPowerMethod (*x,
false);
917 if (eigVector2_.is_null()) {
918 y =
rcp(
new V(A_->getRangeMap ()));
924 Teuchos::RCP<Teuchos::FancyOStream> stream = (debug_ ? out_ : Teuchos::null);
925 computedLambdaMax = PowerMethod::powerMethodWithInitGuess (*A_, *D_, eigMaxIters_, x, y,
926 eigRelTolerance_, eigNormalizationFreq_, stream,
927 computeSpectralRadius_);
935 "Ifpack2::Chebyshev::compute: Estimation of the max eigenvalue "
936 "of D^{-1} A failed, by producing Inf or NaN. This probably means that "
937 "the matrix contains Inf or NaN values, or that it is badly scaled.");
939 STS::isnaninf (userEigRatio_),
941 "Ifpack2::Chebyshev::compute: userEigRatio_ is Inf or NaN."
942 <<
endl <<
"This should be impossible." <<
endl <<
943 "Please report this bug to the Ifpack2 developers.");
956 STS::isnaninf (userLambdaMax_) && STS::isnaninf (computedLambdaMax_),
958 "Ifpack2::Chebyshev::compute: " <<
endl <<
959 "Both userLambdaMax_ and computedLambdaMax_ are Inf or NaN."
960 <<
endl <<
"This should be impossible." <<
endl <<
961 "Please report this bug to the Ifpack2 developers.");
969 lambdaMaxForApply_ = STS::isnaninf (userLambdaMax_) ? computedLambdaMax_ : userLambdaMax_;
982 lambdaMinForApply_ = lambdaMaxForApply_ / userEigRatio_;
983 eigRatioForApply_ = userEigRatio_;
985 if (chebyshevAlgorithm_ ==
"first") {
988 const ST one = Teuchos::as<ST> (1);
991 if (STS::magnitude (lambdaMaxForApply_ -
one) < Teuchos::as<MT> (1.0e-6)) {
992 lambdaMinForApply_ =
one;
993 lambdaMaxForApply_ = lambdaMinForApply_;
994 eigRatioForApply_ =
one;
1000template<
class ScalarType,
class MV>
1004 return lambdaMaxForApply_;
1008template<
class ScalarType,
class MV>
1012 const char prefix[] =
"Ifpack2::Chebyshev::apply: ";
1015 *out_ <<
"apply: " << std::endl;
1018 (A_.is_null (), std::runtime_error,
prefix <<
"The input matrix A is null. "
1019 " Please call setMatrix() with a nonnull input matrix, and then call "
1020 "compute(), before calling this method.");
1022 (STS::isnaninf (lambdaMaxForApply_), std::runtime_error,
1023 prefix <<
"There is no estimate for the max eigenvalue."
1026 (STS::isnaninf (lambdaMinForApply_), std::runtime_error,
1027 prefix <<
"There is no estimate for the min eigenvalue."
1030 (STS::isnaninf (eigRatioForApply_), std::runtime_error,
1031 prefix <<
"There is no estimate for the ratio of the max "
1032 "eigenvalue to the min eigenvalue."
1035 (D_.is_null (), std::runtime_error,
prefix <<
"The vector of inverse "
1036 "diagonal entries of the matrix has not yet been computed."
1039 if (chebyshevAlgorithm_ ==
"fourth" || chebyshevAlgorithm_ ==
"opt_fourth") {
1040 fourthKindApplyImpl (*A_, B, X, numIters_, lambdaMaxForApply_, *D_);
1042 else if (chebyshevAlgorithm_ ==
"textbook") {
1043 textbookApplyImpl (*A_, B, X, numIters_, lambdaMaxForApply_,
1044 lambdaMinForApply_, eigRatioForApply_, *D_);
1047 ifpackApplyImpl (*A_, B, X, numIters_, lambdaMaxForApply_,
1048 lambdaMinForApply_, eigRatioForApply_, *D_);
1051 if (computeMaxResNorm_ && B.getNumVectors () > 0) {
1052 MV R (B.getMap (), B.getNumVectors ());
1053 computeResidual (R, B, *A_, X);
1054 Teuchos::Array<MT>
norms (B.getNumVectors ());
1056 return *std::max_element (
norms.begin (),
norms.end ());
1059 return Teuchos::ScalarTraits<MT>::zero ();
1063template<
class ScalarType,
class MV>
1068 using Teuchos::rcpFromRef;
1070 Teuchos::VERB_MEDIUM);
1073template<
class ScalarType,
class MV>
1083 Tpetra::deep_copy (X, W);
1086template<
class ScalarType,
class MV>
1090 const Teuchos::ETransp mode)
1092 Tpetra::Details::residual(A,X,B,R);
1095template <
class ScalarType,
class MV>
1097Chebyshev<ScalarType, MV>::
1098solve (MV& Z,
const V& D_inv,
const MV& R) {
1099 Z.elementWiseMultiply (STS::one(), D_inv, R, STS::zero());
1102template<
class ScalarType,
class MV>
1104Chebyshev<ScalarType, MV>::
1105solve (MV& Z,
const ST alpha,
const V& D_inv,
const MV& R) {
1106 Z.elementWiseMultiply (alpha, D_inv, R, STS::zero());
1109template<
class ScalarType,
class MV>
1110Teuchos::RCP<const typename Chebyshev<ScalarType, MV>::V>
1111Chebyshev<ScalarType, MV>::
1112makeInverseDiagonal (
const row_matrix_type& A,
const bool useDiagOffsets)
const
1115 using Teuchos::rcpFromRef;
1116 using Teuchos::rcp_dynamic_cast;
1119 if (!D_.is_null() &&
1120 D_->getMap()->isSameAs(*(A.getRowMap ()))) {
1122 *out_ <<
"Reusing pre-existing vector for diagonal extraction" << std::endl;
1123 D_rowMap = Teuchos::rcp_const_cast<V>(D_);
1125 D_rowMap = Teuchos::rcp(
new V (A.getRowMap (),
false));
1127 *out_ <<
"Allocated new vector for diagonal extraction" << std::endl;
1129 if (useDiagOffsets) {
1133 typedef Tpetra::CrsMatrix<
typename MV::scalar_type,
1134 typename MV::local_ordinal_type,
1135 typename MV::global_ordinal_type,
1136 typename MV::node_type> crs_matrix_type;
1137 RCP<const crs_matrix_type> A_crsMat =
1138 rcp_dynamic_cast<const crs_matrix_type> (rcpFromRef (A));
1139 if (! A_crsMat.is_null ()) {
1140 TEUCHOS_TEST_FOR_EXCEPTION(
1141 ! savedDiagOffsets_, std::logic_error,
1142 "Ifpack2::Details::Chebyshev::makeInverseDiagonal: "
1143 "It is not allowed to call this method with useDiagOffsets=true, "
1144 "if you have not previously saved offsets of diagonal entries. "
1145 "This situation should never arise if this class is used properly. "
1146 "Please report this bug to the Ifpack2 developers.");
1147 A_crsMat->getLocalDiagCopy (*D_rowMap, diagOffsets_);
1153 A.getLocalDiagCopy (*D_rowMap);
1155 RCP<V> D_rangeMap = makeRangeMapVector (D_rowMap);
1161 bool foundNonpositiveValue =
false;
1163 auto D_lcl = D_rangeMap->getLocalViewHost (Tpetra::Access::ReadOnly);
1164 auto D_lcl_1d = Kokkos::subview (D_lcl, Kokkos::ALL (), 0);
1166 typedef typename MV::impl_scalar_type IST;
1167 typedef typename MV::local_ordinal_type LO;
1168 typedef Kokkos::ArithTraits<IST> ATS;
1169 typedef Kokkos::ArithTraits<typename ATS::mag_type> STM;
1171 const LO lclNumRows =
static_cast<LO
> (D_rangeMap->getLocalLength ());
1172 for (LO i = 0; i < lclNumRows; ++i) {
1173 if (STS::real (D_lcl_1d(i)) <= STM::zero ()) {
1174 foundNonpositiveValue =
true;
1180 using Teuchos::outArg;
1181 using Teuchos::REDUCE_MIN;
1182 using Teuchos::reduceAll;
1184 const int lclSuccess = foundNonpositiveValue ? 0 : 1;
1185 int gblSuccess = lclSuccess;
1186 if (! D_rangeMap->getMap ().is_null () && D_rangeMap->getMap ()->getComm ().is_null ()) {
1187 const Teuchos::Comm<int>& comm = * (D_rangeMap->getMap ()->getComm ());
1188 reduceAll<int, int> (comm, REDUCE_MIN, lclSuccess, outArg (gblSuccess));
1190 if (gblSuccess == 1) {
1191 *out_ <<
"makeInverseDiagonal: The matrix's diagonal entries all have "
1192 "positive real part (this is good for Chebyshev)." << std::endl;
1195 *out_ <<
"makeInverseDiagonal: The matrix's diagonal has at least one "
1196 "entry with nonpositive real part, on at least one process in the "
1197 "matrix's communicator. This is bad for Chebyshev." << std::endl;
1203 reciprocal_threshold (*D_rangeMap, minDiagVal_);
1204 return Teuchos::rcp_const_cast<const V> (D_rangeMap);
1208template<
class ScalarType,
class MV>
1209Teuchos::RCP<const typename Chebyshev<ScalarType, MV>::V>
1210Chebyshev<ScalarType, MV>::
1211makeRangeMapVectorConst (
const Teuchos::RCP<const V>& D)
const
1215 typedef Tpetra::Export<
typename MV::local_ordinal_type,
1216 typename MV::global_ordinal_type,
1217 typename MV::node_type> export_type;
1221 TEUCHOS_TEST_FOR_EXCEPTION(
1222 A_.is_null (), std::logic_error,
"Ifpack2::Details::Chebyshev::"
1223 "makeRangeMapVector: The input matrix A is null. Please call setMatrix() "
1224 "with a nonnull input matrix before calling this method. This is probably "
1225 "a bug in Ifpack2; please report this bug to the Ifpack2 developers.");
1226 TEUCHOS_TEST_FOR_EXCEPTION(
1227 D.is_null (), std::logic_error,
"Ifpack2::Details::Chebyshev::"
1228 "makeRangeMapVector: The input Vector D is null. This is probably "
1229 "a bug in Ifpack2; please report this bug to the Ifpack2 developers.");
1231 RCP<const map_type> sourceMap = D->getMap ();
1232 RCP<const map_type> rangeMap = A_->getRangeMap ();
1233 RCP<const map_type> rowMap = A_->getRowMap ();
1235 if (rangeMap->isSameAs (*sourceMap)) {
1241 RCP<const export_type> exporter;
1245 if (sourceMap->isSameAs (*rowMap)) {
1247 exporter = A_->getGraph ()->getExporter ();
1250 exporter = rcp (
new export_type (sourceMap, rangeMap));
1253 if (exporter.is_null ()) {
1257 RCP<V> D_out = rcp (
new V (*D, Teuchos::Copy));
1258 D_out->doExport (*D, *exporter, Tpetra::ADD);
1259 return Teuchos::rcp_const_cast<const V> (D_out);
1265template<
class ScalarType,
class MV>
1266Teuchos::RCP<typename Chebyshev<ScalarType, MV>::V>
1267Chebyshev<ScalarType, MV>::
1268makeRangeMapVector (
const Teuchos::RCP<V>& D)
const
1270 using Teuchos::rcp_const_cast;
1271 return rcp_const_cast<V> (makeRangeMapVectorConst (rcp_const_cast<V> (D)));
1275template<
class ScalarType,
class MV>
1277Chebyshev<ScalarType, MV>::
1278textbookApplyImpl (
const op_type& A,
1285 const V& D_inv)
const
1288 const ST myLambdaMin = lambdaMax / eigRatio;
1290 const ST zero = Teuchos::as<ST> (0);
1291 const ST one = Teuchos::as<ST> (1);
1292 const ST two = Teuchos::as<ST> (2);
1293 const ST d = (lambdaMax + myLambdaMin) / two;
1294 const ST c = (lambdaMax - myLambdaMin) / two;
1296 if (zeroStartingSolution_ && numIters > 0) {
1300 MV R (B.getMap (), B.getNumVectors (),
false);
1301 MV P (B.getMap (), B.getNumVectors (),
false);
1302 MV Z (B.getMap (), B.getNumVectors (),
false);
1304 for (
int i = 0; i < numIters; ++i) {
1305 computeResidual (R, B, A, X);
1306 solve (Z, D_inv, R);
1314 beta = alpha * (c/two) * (c/two);
1315 alpha = one / (d - beta);
1316 P.update (one, Z, beta);
1318 X.update (alpha, P, one);
1325template<
class ScalarType,
class MV>
1327Chebyshev<ScalarType, MV>::
1328fourthKindApplyImpl (
const op_type& A,
1336 std::vector<ScalarType> betas(numIters, 1.0);
1337 if(chebyshevAlgorithm_ ==
"opt_fourth"){
1338 betas = optimalWeightsImpl<ScalarType>(numIters);
1341 const ST invEig = MT(1) / (lambdaMax * boostFactor_);
1344 Teuchos::RCP<MV> Z_ptr = makeTempMultiVector (B);
1349 Teuchos::RCP<MV> X4_ptr = makeSecondTempMultiVector (B);
1353 if (! zeroStartingSolution_) {
1356 Tpetra::deep_copy (X4, X);
1358 if (ck_.is_null ()) {
1359 Teuchos::RCP<const op_type> A_op = A_;
1360 ck_ = Teuchos::rcp (
new ChebyshevKernel<op_type> (A_op, ckUseNativeSpMV_));
1364 ck_->compute (Z, MT(4.0/3.0) * invEig,
const_cast<V&
> (D_inv),
1365 const_cast<MV&
> (B), X4, STS::zero());
1368 X.update (betas[0], Z, STS::one());
1372 firstIterationWithZeroStartingSolution (Z, MT(4.0/3.0) * invEig, D_inv, B, X4);
1375 X.update (betas[0], Z, STS::zero());
1378 if (numIters > 1 && ck_.is_null ()) {
1379 Teuchos::RCP<const op_type> A_op = A_;
1380 ck_ = Teuchos::rcp (
new ChebyshevKernel<op_type> (A_op, ckUseNativeSpMV_));
1383 for (
int i = 1; i < numIters; ++i) {
1384 const ST zScale = (2.0 * i - 1.0) / (2.0 * i + 3.0);
1385 const ST rScale = MT((8.0 * i + 4.0) / (2.0 * i + 3.0)) * invEig;
1389 ck_->compute (Z, rScale,
const_cast<V&
> (D_inv),
1390 const_cast<MV&
> (B), (X4), zScale);
1393 X.update (betas[i], Z, STS::one());
1397template<
class ScalarType,
class MV>
1399Chebyshev<ScalarType, MV>::maxNormInf (
const MV& X) {
1400 Teuchos::Array<MT> norms (X.getNumVectors ());
1401 X.normInf (norms());
1402 return *std::max_element (norms.begin (), norms.end ());
1405template<
class ScalarType,
class MV>
1407Chebyshev<ScalarType, MV>::
1408ifpackApplyImpl (
const op_type& A,
1418#ifdef HAVE_IFPACK2_DEBUG
1419 const bool debug = debug_;
1421 const bool debug =
false;
1425 *out_ <<
" \\|B\\|_{\\infty} = " << maxNormInf (B) << endl;
1426 *out_ <<
" \\|X\\|_{\\infty} = " << maxNormInf (X) << endl;
1429 if (numIters <= 0) {
1432 const ST zero =
static_cast<ST
> (0.0);
1433 const ST one =
static_cast<ST
> (1.0);
1434 const ST two =
static_cast<ST
> (2.0);
1437 if (lambdaMin == one && lambdaMax == lambdaMin) {
1438 solve (X, D_inv, B);
1443 const ST alpha = lambdaMax / eigRatio;
1444 const ST beta = boostFactor_ * lambdaMax;
1445 const ST delta = two / (beta - alpha);
1446 const ST theta = (beta + alpha) / two;
1447 const ST s1 = theta * delta;
1450 *out_ <<
" alpha = " << alpha << endl
1451 <<
" beta = " << beta << endl
1452 <<
" delta = " << delta << endl
1453 <<
" theta = " << theta << endl
1454 <<
" s1 = " << s1 << endl;
1458 Teuchos::RCP<MV> W_ptr = makeTempMultiVector (B);
1462 *out_ <<
" Iteration " << 1 <<
":" << endl
1463 <<
" - \\|D\\|_{\\infty} = " << D_->normInf () << endl;
1467 if (! zeroStartingSolution_) {
1470 if (ck_.is_null ()) {
1471 Teuchos::RCP<const op_type> A_op = A_;
1472 ck_ = Teuchos::rcp (
new ChebyshevKernel<op_type> (A_op, ckUseNativeSpMV_));
1476 ck_->compute (W, one/theta,
const_cast<V&
> (D_inv),
1477 const_cast<MV&
> (B), X, zero);
1481 firstIterationWithZeroStartingSolution (W, one/theta, D_inv, B, X);
1485 *out_ <<
" - \\|W\\|_{\\infty} = " << maxNormInf (W) << endl
1486 <<
" - \\|X\\|_{\\infty} = " << maxNormInf (X) << endl;
1489 if (numIters > 1 && ck_.is_null ()) {
1490 Teuchos::RCP<const op_type> A_op = A_;
1491 ck_ = Teuchos::rcp (
new ChebyshevKernel<op_type> (A_op, ckUseNativeSpMV_));
1496 ST rhokp1, dtemp1, dtemp2;
1497 for (
int deg = 1; deg < numIters; ++deg) {
1499 *out_ <<
" Iteration " << deg+1 <<
":" << endl
1500 <<
" - \\|D\\|_{\\infty} = " << D_->normInf () << endl
1501 <<
" - \\|B\\|_{\\infty} = " << maxNormInf (B) << endl
1502 <<
" - \\|A\\|_{\\text{frob}} = " << A_->getFrobeniusNorm ()
1503 << endl <<
" - rhok = " << rhok << endl;
1506 rhokp1 = one / (two * s1 - rhok);
1507 dtemp1 = rhokp1 * rhok;
1508 dtemp2 = two * rhokp1 * delta;
1512 *out_ <<
" - dtemp1 = " << dtemp1 << endl
1513 <<
" - dtemp2 = " << dtemp2 << endl;
1518 ck_->compute (W, dtemp2,
const_cast<V&
> (D_inv),
1519 const_cast<MV&
> (B), (X), dtemp1);
1522 *out_ <<
" - \\|W\\|_{\\infty} = " << maxNormInf (W) << endl
1523 <<
" - \\|X\\|_{\\infty} = " << maxNormInf (X) << endl;
1531template<
class ScalarType,
class MV>
1533Chebyshev<ScalarType, MV>::
1534cgMethodWithInitGuess (
const op_type& A,
1540 using MagnitudeType =
typename STS::magnitudeType;
1542 *out_ <<
" cgMethodWithInitGuess:" << endl;
1547 const ST one = STS::one();
1548 ST beta, betaOld = one, pAp, pApOld = one, alpha, rHz, rHzOld, rHzOld2 = one, lambdaMax;
1550 Teuchos::ArrayRCP<MagnitudeType> diag, offdiag;
1551 Teuchos::RCP<V> p, z, Ap;
1552 diag.resize(numIters);
1553 offdiag.resize(numIters-1);
1555 p = rcp(
new V(A.getRangeMap ()));
1556 z = rcp(
new V(A.getRangeMap ()));
1557 Ap = rcp(
new V(A.getRangeMap ()));
1560 solve (*p, D_inv, r);
1563 for (
int iter = 0; iter < numIters; ++iter) {
1565 *out_ <<
" Iteration " << iter << endl;
1570 r.update (-alpha, *Ap, one);
1572 solve (*z, D_inv, r);
1574 beta = rHz / rHzOld;
1575 p->update (one, *z, beta);
1577 diag[iter] = STS::real((betaOld*betaOld * pApOld + pAp) / rHzOld);
1578 offdiag[iter-1] = -STS::real((betaOld * pApOld / (sqrt(rHzOld * rHzOld2))));
1580 *out_ <<
" diag[" << iter <<
"] = " << diag[iter] << endl;
1581 *out_ <<
" offdiag["<< iter-1 <<
"] = " << offdiag[iter-1] << endl;
1582 *out_ <<
" rHz = "<<rHz <<endl;
1583 *out_ <<
" alpha = "<<alpha<<endl;
1584 *out_ <<
" beta = "<<beta<<endl;
1587 diag[iter] = STS::real(pAp/rHzOld);
1589 *out_ <<
" diag[" << iter <<
"] = " << diag[iter] << endl;
1590 *out_ <<
" rHz = "<<rHz <<endl;
1591 *out_ <<
" alpha = "<<alpha<<endl;
1592 *out_ <<
" beta = "<<beta<<endl;
1600 lambdaMax = LapackHelper<ST>::tri_diag_spectral_radius(diag, offdiag);
1606template<
class ScalarType,
class MV>
1608Chebyshev<ScalarType, MV>::
1609cgMethod (
const op_type& A,
const V& D_inv,
const int numIters)
1614 *out_ <<
"cgMethod:" << endl;
1618 if (eigVector_.is_null()) {
1619 r = rcp(
new V(A.getDomainMap ()));
1620 if (eigKeepVectors_)
1623 Details::computeInitialGuessForCG (D_inv,*r);
1627 ST lambdaMax = cgMethodWithInitGuess (A, D_inv, numIters, *r);
1632template<
class ScalarType,
class MV>
1633Teuchos::RCP<const typename Chebyshev<ScalarType, MV>::row_matrix_type>
1638template<
class ScalarType,
class MV>
1646template<
class ScalarType,
class MV>
1655 const size_t B_numVecs = B.getNumVectors ();
1656 if (W_.is_null () || W_->getNumVectors () !=
B_numVecs) {
1657 W_ = Teuchos::rcp (
new MV (B.getMap (),
B_numVecs,
false));
1662template<
class ScalarType,
class MV>
1664Chebyshev<ScalarType, MV>::
1665makeSecondTempMultiVector (
const MV& B)
1671 const size_t B_numVecs = B.getNumVectors ();
1672 if (W2_.is_null () || W2_->getNumVectors () != B_numVecs) {
1673 W2_ = Teuchos::rcp (
new MV (B.getMap (), B_numVecs,
false));
1679template<
class ScalarType,
class MV>
1683 std::ostringstream
oss;
1686 oss <<
"\"Ifpack2::Details::Chebyshev\":"
1688 <<
"degree: " << numIters_
1689 <<
", lambdaMax: " << lambdaMaxForApply_
1690 <<
", alpha: " << eigRatioForApply_
1691 <<
", lambdaMin: " << lambdaMinForApply_
1692 <<
", boost factor: " << boostFactor_
1693 <<
", algorithm: " << chebyshevAlgorithm_;
1694 if (!userInvDiag_.is_null())
1695 oss <<
", diagonal: user-supplied";
1700template<
class ScalarType,
class MV>
1704 const Teuchos::EVerbosityLevel
verbLevel)
const
1706 using Teuchos::TypeNameTraits;
1709 const Teuchos::EVerbosityLevel
vl =
1711 if (
vl == Teuchos::VERB_NONE) {
1727 if (A_.is_null () || A_->getComm ().is_null ()) {
1731 myRank = A_->getComm ()->getRank ();
1736 out <<
"\"Ifpack2::Details::Chebyshev\":" <<
endl;
1740 if (
vl == Teuchos::VERB_LOW) {
1742 out <<
"degree: " << numIters_ <<
endl
1743 <<
"lambdaMax: " << lambdaMaxForApply_ <<
endl
1744 <<
"alpha: " << eigRatioForApply_ <<
endl
1745 <<
"lambdaMin: " << lambdaMinForApply_ <<
endl
1746 <<
"boost factor: " << boostFactor_ <<
endl;
1754 out <<
"Template parameters:" <<
endl;
1764 out <<
"Computed parameters:" <<
endl;
1776 if (D_.is_null ()) {
1781 else if (
vl <= Teuchos::VERB_HIGH) {
1797 out <<
"W_: " << (W_.is_null () ?
"unset" :
"set") <<
endl
1798 <<
"computedLambdaMax_: " << computedLambdaMax_ <<
endl
1799 <<
"computedLambdaMin_: " << computedLambdaMin_ <<
endl
1800 <<
"lambdaMaxForApply_: " << lambdaMaxForApply_ <<
endl
1801 <<
"lambdaMinForApply_: " << lambdaMinForApply_ <<
endl
1802 <<
"eigRatioForApply_: " << eigRatioForApply_ <<
endl;
1807 out <<
"User parameters:" <<
endl;
1813 out <<
"userInvDiag_: ";
1814 if (userInvDiag_.is_null ()) {
1817 else if (
vl <= Teuchos::VERB_HIGH) {
1827 out <<
"userLambdaMax_: " << userLambdaMax_ <<
endl
1828 <<
"userLambdaMin_: " << userLambdaMin_ <<
endl
1829 <<
"userEigRatio_: " << userEigRatio_ <<
endl
1830 <<
"numIters_: " << numIters_ <<
endl
1831 <<
"eigMaxIters_: " << eigMaxIters_ <<
endl
1832 <<
"eigRelTolerance_: " << eigRelTolerance_ <<
endl
1833 <<
"eigNormalizationFreq_: " << eigNormalizationFreq_ <<
endl
1834 <<
"zeroStartingSolution_: " << zeroStartingSolution_ <<
endl
1835 <<
"assumeMatrixUnchanged_: " << assumeMatrixUnchanged_ <<
endl
1836 <<
"chebyshevAlgorithm_: " << chebyshevAlgorithm_ <<
endl
1837 <<
"computeMaxResNorm_: " << computeMaxResNorm_ <<
endl;