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