00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #ifndef CONJUGATE_GRADIENT_HPP
00022 #define CONJUGATE_GRADIENT_HPP
00023
00024 #include <ConjugateGradientOptions.hpp>
00025 #include <GetParameter.hpp>
00026
00036 class ConjugateGradient
00037 {
00038 private:
00039 real_t __epsilon;
00040 int __maxiter;
00041
00042 GetParameter<ConjugateGradientOptions> __options;
00043
00044 public:
00045 template <typename VectorType,
00046 typename MatrixType,
00047 typename PreconditionerType>
00048 ConjugateGradient(const VectorType& f,
00049 const MatrixType& A,
00050 const PreconditionerType& C,
00051 VectorType& x,
00052 const int maxiter = -1,
00053 const real_t epsilon = -1.)
00054 {
00055 if (epsilon == -1) {
00056 __epsilon = __options.value().epsilon();
00057 } else {
00058 __epsilon = epsilon;
00059 }
00060
00061 if (maxiter == -1) {
00062 __maxiter = __options.value().maxiter();
00063 } else {
00064 __maxiter = maxiter;
00065 }
00066
00067 ffout(2) << "- conjugate gradient\n";
00068 ffout(3) << " epsilon = "
00069 << std::setiosflags(std::ios_base::scientific)
00070 << __epsilon
00071 << std::resetiosflags(std::ios_base::scientific)
00072 << '\n';
00073 ffout(3) << " maximum number of iterations: " << __maxiter << '\n';
00074
00075 VectorType h(x.size());
00076 VectorType b(f);
00077
00078 VectorType g(b.size());
00079 VectorType cg = b;
00080
00081 real_t gcg=0;
00082 real_t gcg0=1;
00083
00084 real_t relativeEpsilon = __epsilon;
00085
00086 for (int i=1; i<=__maxiter; ++i) {
00087 if (i==1) {
00088 A.timesX(x,h);
00089
00090 cg -= h;
00091
00092 C.computes(cg, g);
00093
00094 gcg = g * cg;
00095
00096 h=g;
00097 }
00098
00099 A.timesX(h,b);
00100
00101 real_t hAh = h*b;
00102
00103 if (hAh==0) {
00104 hAh=1.;
00105 }
00106 real_t ro = gcg/hAh;
00107 cg -= ro*b;
00108
00109 VectorType b2 = b;
00110 C.computes(b2,b);
00111
00112 x+=ro*h;
00113 g-=ro*b;
00114
00115 real_t gamma=gcg;
00116 gcg = g * cg;
00117
00118 if ((i == 1)&&(gcg != 0)) {
00119 relativeEpsilon = __epsilon*gcg;
00120 gcg0=gcg;
00121 ffout(2) << " initial residu: "
00122 << std::setiosflags(std::ios_base::scientific)
00123 << gcg
00124 << std::resetiosflags(std::ios_base::scientific)
00125 << '\n';
00126 }
00127 ffout(3) << " - iteration "
00128 << std::setw(6)
00129 << i
00130 << "\tresidu: "
00131 << std::setiosflags(std::ios_base::scientific)
00132 << gcg/gcg0;
00133 ffout(4) << "\tabsolute: " << gcg;
00134 ffout(3) << std::resetiosflags(std::ios_base::scientific)
00135 << '\n';
00136
00137 if (gcg<relativeEpsilon) {
00138 break;
00139 }
00140
00141 gamma=gcg/gamma;
00142
00143 h *= gamma;
00144 h += g;
00145 }
00146
00147 if (gcg > relativeEpsilon) {
00148 ffout(2) << " conjugate gradient: *NOT CONVERGED*\n";
00149 ffout(2) << " - epsilon: " << __epsilon << '\n';
00150 ffout(2) << " - relative residu : " << gcg/gcg0 << '\n';
00151 ffout(2) << " - absolute residu : " << gcg << '\n';
00152 }
00153
00154 if (StreamCenter::instance().getDebugLevel()>3) {
00155 A.timesX(x,h);
00156 h -= b;
00157 ffout(4) << "- final *real* residu : " << h*h << '\n';
00158 }
00159 ffout(2) << "- conjugate gradient: done\n";
00160 }
00161 };
00162 #endif // CONJUGATE_GRADIENT_HPP