MueLu  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
MueLu_CGSolver_def.hpp
Go to the documentation of this file.
1 // @HEADER
2 // *****************************************************************************
3 // MueLu: A package for multigrid based preconditioning
4 //
5 // Copyright 2012 NTESS and the MueLu contributors.
6 // SPDX-License-Identifier: BSD-3-Clause
7 // *****************************************************************************
8 // @HEADER
9 
10 #ifndef MUELU_CGSOLVER_DEF_HPP
11 #define MUELU_CGSOLVER_DEF_HPP
12 
13 #include <Xpetra_MatrixFactory.hpp>
14 #include <Xpetra_MatrixFactory2.hpp>
15 #include <Xpetra_MatrixMatrix.hpp>
16 
17 #include "MueLu_Utilities.hpp"
18 #include "MueLu_Constraint.hpp"
19 #include "MueLu_Monitor.hpp"
20 
21 #include "MueLu_CGSolver_decl.hpp"
22 
23 namespace MueLu {
24 
25 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
27  : nIts_(Its) {}
28 
29 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
30 void CGSolver<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Iterate(const Matrix& Aref, const Constraint& C, const Matrix& P0, RCP<Matrix>& finalP) const {
31  // Note: this function matrix notations follow Saad's "Iterative methods", ed. 2, pg. 246
32  // So, X is the unknown prolongator, P's are conjugate directions, Z's are preconditioned P's
33  PrintMonitor m(*this, "CG iterations");
34 
35  if (nIts_ == 0) {
36  finalP = MatrixFactory2::BuildCopy(rcpFromRef(P0));
37  return;
38  }
39 
40  RCP<const Matrix> A = rcpFromRef(Aref);
41  const auto rowMap = A->getRowMap();
43  A->getLocalDiagCopy(*invDiag);
44  invDiag->reciprocal(*invDiag);
45 
46  bool useTpetra = (A->getRowMap()->lib() == Xpetra::UseTpetra);
47 
48  Teuchos::FancyOStream& mmfancy = this->GetOStream(Statistics2);
49 
51 
52  RCP<Matrix> X, P, R, Z, AP;
53  RCP<Matrix> newX, tmpAP;
54 #ifndef TWO_ARG_MATRIX_ADD
55  RCP<Matrix> newR, newP;
56 #endif
57 
58  SC oldRZ, newRZ, alpha, beta, app;
59 
60  // T is used only for projecting onto
61  RCP<CrsMatrix> T_ = CrsMatrixFactory::Build(C.GetPattern());
62  T_->fillComplete(P0.getDomainMap(), P0.getRangeMap());
63  RCP<Matrix> T = rcp(new CrsMatrixWrap(T_));
64 
65  // Initial P0 would only be used for multiplication
66  X = rcp_const_cast<Matrix>(rcpFromRef(P0));
67 
68  tmpAP = MatrixMatrix::Multiply(*A, false, *X, false, mmfancy, true /*doFillComplete*/, true /*optimizeStorage*/);
69  C.Apply(*tmpAP, *T);
70 
71  // R_0 = -A*X_0
73 
74  R->scale(-one);
75 
76  // Z_0 = M^{-1}R_0
78  Z->leftScale(*invDiag);
79 
80  // P_0 = Z_0
82 
83  oldRZ = Utilities::Frobenius(*R, *Z);
84 
85  for (size_t i = 0; i < nIts_; i++) {
86  // AP = constrain(A*P)
87  if (i == 0 || useTpetra) {
88  // Construct the MxM pattern from scratch
89  // This is done by default for Tpetra as the three argument version requires tmpAP
90  // to *not* be locally indexed which defeats the purpose
91  // TODO: need a three argument Tpetra version which allows reuse of already fill-completed matrix
92  tmpAP = MatrixMatrix::Multiply(*A, false, *P, false, mmfancy, true /*doFillComplete*/, true /*optimizeStorage*/);
93  } else {
94  // Reuse the MxM pattern
95  tmpAP = MatrixMatrix::Multiply(*A, false, *P, false, tmpAP, mmfancy, true /*doFillComplete*/, true /*optimizeStorage*/);
96  }
97  C.Apply(*tmpAP, *T);
98  AP = T;
99 
100  app = Utilities::Frobenius(*AP, *P);
102  // It happens, for instance, if P = 0
103  // For example, if we use TentativePFactory for both nonzero pattern and initial guess
104  // I think it might also happen because of numerical breakdown, but we don't test for that yet
105  if (i == 0)
106  X = MatrixFactory2::BuildCopy(rcpFromRef(P0));
107  break;
108  }
109 
110  // alpha = (R_i, Z_i)/(A*P_i, P_i)
111  alpha = oldRZ / app;
112  this->GetOStream(Runtime1, 1) << "alpha = " << alpha << std::endl;
113 
114  // X_{i+1} = X_i + alpha*P_i
115 #ifndef TWO_ARG_MATRIX_ADD
116  newX = Teuchos::null;
117  MatrixMatrix::TwoMatrixAdd(*P, false, alpha, *X, false, one, newX, mmfancy);
118  newX->fillComplete(P0.getDomainMap(), P0.getRangeMap());
119  X.swap(newX);
120 #else
121  MatrixMatrix::TwoMatrixAdd(*P, false, alpha, *X, one);
122 #endif
123 
124  if (i == nIts_ - 1)
125  break;
126 
127  // R_{i+1} = R_i - alpha*A*P_i
128 #ifndef TWO_ARG_MATRIX_ADD
129  newR = Teuchos::null;
130  MatrixMatrix::TwoMatrixAdd(*AP, false, -alpha, *R, false, one, newR, mmfancy);
131  newR->fillComplete(P0.getDomainMap(), P0.getRangeMap());
132  R.swap(newR);
133 #else
134  MatrixMatrix::TwoMatrixAdd(*AP, false, -alpha, *R, one);
135 #endif
136 
137  // Z_{i+1} = M^{-1} R_{i+1}
138  Z = MatrixFactory2::BuildCopy(R);
139  Z->leftScale(*invDiag);
140 
141  // beta = (R_{i+1}, Z_{i+1})/(R_i, Z_i)
142  newRZ = Utilities::Frobenius(*R, *Z);
143  beta = newRZ / oldRZ;
144 
145  // P_{i+1} = Z_{i+1} + beta*P_i
146 #ifndef TWO_ARG_MATRIX_ADD
147  newP = Teuchos::null;
148  MatrixMatrix::TwoMatrixAdd(*P, false, beta, *Z, false, one, newP, mmfancy);
149  newP->fillComplete(P0.getDomainMap(), P0.getRangeMap());
150  P.swap(newP);
151 #else
152  MatrixMatrix::TwoMatrixAdd(*Z, false, one, *P, beta);
153 #endif
154 
155  oldRZ = newRZ;
156  }
157 
158  finalP = X;
159 }
160 
161 } // namespace MueLu
162 
163 #endif // ifndef MUELU_CGSOLVER_DECL_HPP
Constraint space information for the potential prolongator.
void swap(RCP< T > &r_ptr)
RCP< const CrsGraph > GetPattern() const
Print even more statistics.
void Iterate(const Matrix &A, const Constraint &C, const Matrix &P0, RCP< Matrix > &P) const
Iterate.
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
static RCP< Xpetra::Matrix< Scalar, LocalOrdinal, GlobalOrdinal, Node > > BuildCopy(const RCP< const Xpetra::Matrix< Scalar, LocalOrdinal, GlobalOrdinal, Node > > A)
static RCP< Vector > Build(const Teuchos::RCP< const Map > &map, bool zeroOut=true)
void Apply(const Matrix &P, Matrix &Projected) const
Apply constraint.
Scalar SC
static Scalar Frobenius(const Xpetra::Matrix< Scalar, LocalOrdinal, GlobalOrdinal, Node > &A, const Xpetra::Matrix< Scalar, LocalOrdinal, GlobalOrdinal, Node > &B)
Frobenius inner product of two matrices.
Description of what is happening (more verbose)