00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #ifndef GMRES_HPP
00022 #define GMRES_HPP
00023
00024 #include <GMRESOptions.hpp>
00025 #include <GetParameter.hpp>
00026
00027
00028 class GMRES
00029 {
00030 private:
00031 GetParameter<GMRESOptions>
00032 __options;
00034 const real_t __epsilon;
00035 const int __maxiter;
00036 const size_t __m;
00045 void __givens(const real_t& beta,
00046 Vector<Vector<real_t> >& H,
00047 Vector<real_t>& y)
00048 {
00049 ffout(3) << std::setiosflags(std::ios_base::scientific);
00050
00051 y = 0;
00052 Vector<real_t> b(H.size());
00053 b = 0;
00054 b[0]=beta;
00055
00056 for (size_t i=0; i<H.size()-1; ++i) {
00057 const real_t h0 = H[i][i];
00058 const real_t h1 = H[i+1][i];
00059 const real_t r = std::sqrt(h0*h0 + h1*h1);
00060 const real_t c = h0/r;
00061 const real_t s = h1/r;
00062
00063 for (size_t j=i; j<H.size()-1; ++j) {
00064 real_t& h_i_j = H[i][j];
00065 real_t& h_ip1_j = H[i+1][j];
00066
00067 const real_t newH_i_j = c*h_i_j + s*h_ip1_j;
00068 const real_t newH_ip1_j = c*h_ip1_j - s*h_i_j;
00069
00070 h_i_j = newH_i_j;
00071 h_ip1_j = newH_ip1_j;
00072 }
00073
00074 const real_t newB_i = c*b[i] + s*b[i+1];
00075 const real_t newB_ip1 = c*b[i+1] - s*b[i];
00076
00077 b[i] = newB_i;
00078 b[i+1] = newB_ip1;
00079 }
00080
00081 for (int i = H.size()-2; i>=0; --i) {
00082 real_t sum = b[i];
00083 for (int j=H.size()-2; j>i; --j) {
00084 sum -= H[i][j]*y[j];
00085 }
00086 y[i] = sum / H[i][i];
00087 }
00088
00089 ffout(3) << std::resetiosflags(std::ios_base::scientific);
00090 }
00091
00092 public:
00093 template <typename VectorType,
00094 typename MatrixType,
00095 typename PreconditionerType>
00096 GMRES(const VectorType& b,
00097 const MatrixType& A,
00098 const PreconditionerType& P,
00099 VectorType& x)
00100 : __epsilon(__options.value().epsilon()),
00101 __maxiter(__options.value().maxiter()),
00102 __m(__options.value().basis())
00103 {
00104 ffout(2) << "- general minimum residual method (m)\n";
00105 ffout(3) << " epsilon = "
00106 << std::setiosflags(std::ios_base::scientific)
00107 << __epsilon
00108 << std::resetiosflags(std::ios_base::scientific)
00109 << '\n';
00110 ffout(3) << " number of Krylov basis vectors: " << __m << '\n';
00111 ffout(3) << " maximum number of iterations: " << __maxiter << '\n';
00112
00113
00114 VectorType w(b.size());
00115 VectorType z(b.size());
00116
00117 Vector<VectorType> V(__m+1);
00118 for (size_t i=0; i<V.size(); ++i) {
00119 V[i].resize(b.size());
00120 }
00121
00122
00123 Vector<Vector<real_t> > H;
00124 H.resize(__m+1);
00125 for (size_t k=0; k< H.size(); ++k) {
00126 H[k].resize(__m);
00127 H[k]=0;
00128 }
00129
00130 real_t normb = 0;
00131 {
00132 VectorType P_1b(b.size());
00133 P.computes(b,P_1b);
00134 normb = Norm(P_1b);
00135 }
00136
00137 VectorType Ax(x.size());
00138 A.timesX(x,Ax);
00139
00140 VectorType Pr(b);
00141 Pr -= Ax;
00142
00143 VectorType r(b.size());
00144
00145 P.computes(Pr,r);
00146
00147 real_t normPr = Norm(Pr);
00148
00149 ffout(2) << " initial residu: "
00150 << std::setiosflags(std::ios_base::scientific)
00151 << normPr
00152 << std::resetiosflags(std::ios_base::scientific)
00153 << '\n';
00154
00155 bool converged = (normPr<=__epsilon*normb);
00156 if (not converged) {
00157 for (int iteration=1; iteration<=__maxiter; ++iteration) {
00158 real_t beta = Norm(r);
00159 V[0] = (1./beta) * r;
00160
00161 for (size_t j=0; j<__m; ++j) {
00162 A.timesX(V[j],z);
00163 P.computes(z, w);
00164
00165 for (size_t i=0; i<=j; ++i) {
00166 H[i][j] = w * V[i];
00167 w -= H[i][j] * V[i];
00168 }
00169 H[j+1][j] = Norm(w);
00170 if (H[j+1][j] != 0)
00171 V[j+1] = (1./H[j+1][j]) * w;
00172 else {
00173 throw ErrorHandler(__FILE__,__LINE__,
00174 "singular matrix!",
00175 ErrorHandler::normal);
00176 }
00177 }
00178
00179 Vector<real_t> y(__m);
00180 this->__givens(beta, H, y);
00181
00182 for (size_t j=0; j<__m; ++j) {
00183 x += y[j]*V[j];
00184 }
00185
00186 A.timesX(x,Ax);
00187 Pr = b;
00188 Pr -= Ax;
00189
00190 normPr = Norm(Pr);
00191
00192 ffout(3) << " - iteration "
00193 << std::setw(6)
00194 << iteration
00195 << "\tresidu: "
00196 << std::setiosflags(std::ios_base::scientific)
00197 << normPr/normb;
00198 ffout(4) << "\tabsolute: " << normPr;
00199 ffout(3) << std::resetiosflags(std::ios_base::scientific)
00200 << '\n';
00201
00202 if (normPr < normb * __epsilon) {
00203 converged = true;
00204 break;
00205 }
00206
00207 P.computes(Pr,r);
00208 }
00209 }
00210
00211 if (not converged) {
00212 ffout(2) << " general minimum residual : *NOT CONVERGED*\n";
00213 ffout(2) << " - m: " << __m << '\n';
00214 ffout(2) << " - epsilon: " << __epsilon << '\n';
00215 ffout(2) << " - relative residu : " << normPr/normb << '\n';
00216 ffout(2) << " - absolute residu : " << normPr << '\n';
00217 }
00218
00219 if (StreamCenter::instance().getDebugLevel()>3) {
00220 A.timesX(x,Ax);
00221 Ax -= b;
00222 ffout(4) << "- final *real* residu : " << Ax*Ax << '\n';
00223 }
00224
00225 ffout(2) << "- general minimum residual method (m): done\n";
00226 }
00227 };
00228
00229 #endif // GMRES_HPP