00001 #ifndef SOLVER_CG_H
00002 #define SOLVER_CG_H
00003
00004
00005 #include <lac/solver_cuda.h>
00006 #include <lac/tridiagonal_matrix.h>
00007
00008 template <class VECTOR = ::Vector<double> >
00009 class SolverCG : public Solver<VECTOR>
00010 {
00011 public:
00016 struct AdditionalData
00017 {
00023 bool log_coefficients;
00024
00032 bool compute_condition_number;
00033
00041 bool compute_all_condition_numbers;
00042
00049 bool compute_eigenvalues;
00050
00056 AdditionalData (const bool log_coefficients = false,
00057 const bool compute_condition_number = false,
00058 const bool compute_all_condition_numbers = false,
00059 const bool compute_eigenvalues = false);
00060 };
00061
00065 SolverCG (::SolverControl &cn,
00066 ::VectorMemory<VECTOR> &mem,
00067 const AdditionalData &data = AdditionalData());
00068
00074 SolverCG (::SolverControl &cn,
00075 const AdditionalData &data=AdditionalData());
00076
00080 virtual ~SolverCG ();
00081
00086 template <class MATRIX, class PRECONDITIONER>
00087 void
00088 solve (const MATRIX &A,
00089 VECTOR &x,
00090 const VECTOR &b,
00091 const PRECONDITIONER &precondition);
00092
00093 protected:
00100 virtual double criterion();
00101
00111 virtual void print_vectors(const unsigned int step,
00112 const VECTOR& x,
00113 const VECTOR& r,
00114 const VECTOR& d) const;
00115
00122 VECTOR *Vr;
00123 VECTOR *Vp;
00124 VECTOR *Vz;
00125 VECTOR *VAp;
00126
00137 double res2;
00138
00142 AdditionalData additional_data;
00143
00144 private:
00145 void cleanup();
00146 };
00147
00150
00151
00152
00153 template <class VECTOR>
00154 inline
00155 SolverCG<VECTOR>::AdditionalData::
00156 AdditionalData (const bool log_coefficients,
00157 const bool compute_condition_number,
00158 const bool compute_all_condition_numbers,
00159 const bool compute_eigenvalues)
00160 :
00161 log_coefficients (log_coefficients),
00162 compute_condition_number(compute_condition_number),
00163 compute_all_condition_numbers(compute_all_condition_numbers),
00164 compute_eigenvalues(compute_eigenvalues)
00165 {}
00166
00167
00168
00169 template <class VECTOR>
00170 SolverCG<VECTOR>::SolverCG (::SolverControl &cn,
00171 ::VectorMemory<VECTOR> &mem,
00172 const AdditionalData &data)
00173 :
00174 Solver<VECTOR>(cn,mem),
00175 additional_data(data)
00176 {}
00177
00178
00179
00180 template <class VECTOR>
00181 SolverCG<VECTOR>::SolverCG (::SolverControl &cn,
00182 const AdditionalData &data)
00183 :
00184 Solver<VECTOR>(cn),
00185 additional_data(data)
00186 {}
00187
00188
00189
00190 template <class VECTOR>
00191 SolverCG<VECTOR>::~SolverCG ()
00192 {}
00193
00194
00195
00196 template <class VECTOR>
00197 double
00198 SolverCG<VECTOR>::criterion()
00199 {
00200 return std::sqrt(res2);
00201 }
00202
00203
00204
00205 template <class VECTOR>
00206 void
00207 SolverCG<VECTOR>::cleanup()
00208 {
00209 this->memory.free(Vr);
00210 this->memory.free(Vp);
00211 this->memory.free(Vz);
00212 this->memory.free(VAp);
00213 ::deallog.pop();
00214 }
00215
00216
00217
00218 template <class VECTOR>
00219 void
00220 SolverCG<VECTOR>::print_vectors(const unsigned int,
00221 const VECTOR&,
00222 const VECTOR&,
00223 const VECTOR&) const
00224 {}
00225
00226
00227
00228 template <class VECTOR>
00229 template <class MATRIX, class PRECONDITIONER>
00230 void
00231 SolverCG<VECTOR>::solve (const MATRIX &A,
00232 VECTOR &x,
00233 const VECTOR &b,
00234 const PRECONDITIONER &precondition)
00235 {
00236 ::SolverControl::State conv=::SolverControl::iterate;
00237
00238 ::deallog.push("cg");
00239
00240
00241 Vr = this->memory.alloc();
00242 Vp = this->memory.alloc();
00243 Vz = this->memory.alloc();
00244 VAp = this->memory.alloc();
00245
00246
00247 bool do_eigenvalues = additional_data.compute_condition_number
00248 | additional_data.compute_all_condition_numbers
00249 | additional_data.compute_eigenvalues;
00250 double eigen_beta_alpha = 0;
00251
00252
00253
00254 std::vector<double> diagonal;
00255 std::vector<double> offdiagonal;
00256
00257 try {
00258
00259 VECTOR& g = *Vr;
00260 VECTOR& h = *Vp;
00261 VECTOR& d = *Vz;
00262 VECTOR& Ad = *VAp;
00263
00264
00265
00266 g.reinit(x, true);
00267 h.reinit(x, true);
00268 d.reinit(x, true);
00269 Ad.reinit(x, true);
00270
00271
00272 int it=0;
00273 double res,gh,alpha,beta;
00274
00275
00276
00277
00278 if (!x.all_zero())
00279 {
00280 A.vmult(g,x);
00281 g.sadd(-1.,1.,b);
00282 }
00283 else
00284 g = b;
00285 res = g.l2_norm();
00286
00287 conv = this->control().check(0,res);
00288 if (conv)
00289 {
00290 cleanup();
00291 return;
00292 }
00293
00294 g *= -1.;
00295 precondition.vmult(h,g);
00296
00297 d.equ(-1.,h);
00298
00299 gh = g*h;
00300
00301 while (conv == ::SolverControl::iterate)
00302 {
00303 it++;
00304 A.vmult(Ad,d);
00305
00306 alpha = d*Ad;
00307 alpha = gh/alpha;
00308
00309 g.add(alpha,Ad);
00310 x.add(alpha,d );
00311 res = g.l2_norm();
00312
00313 print_vectors(it, x, g, d);
00314
00315 conv = this->control().check(it,res);
00316 if (conv)
00317 break;
00318
00319 precondition.vmult(h,g);
00320
00321 beta = gh;
00322 gh = g*h;
00323 beta = gh/beta;
00324
00325 if (additional_data.log_coefficients)
00326 ::deallog << "alpha-beta:" << alpha << '\t' << beta << std::endl;
00327
00328
00329
00330
00331 if (do_eigenvalues)
00332 {
00333 diagonal.push_back(1./alpha + eigen_beta_alpha);
00334 eigen_beta_alpha = beta/alpha;
00335 offdiagonal.push_back(std::sqrt(beta)/alpha);
00336 }
00337
00338 if (additional_data.compute_all_condition_numbers && (diagonal.size()>1))
00339 {
00340 ::TridiagonalMatrix<double> T(diagonal.size(), true);
00341 for (unsigned int i=0;i<diagonal.size();++i)
00342 {
00343 T(i,i) = diagonal[i];
00344 if (i< diagonal.size()-1)
00345 T(i,i+1) = offdiagonal[i];
00346 }
00347 T.compute_eigenvalues();
00348 ::deallog << "Condition number estimate: " <<
00349 T.eigenvalue(T.n()-1)/T.eigenvalue(0) << std::endl;
00350 }
00351
00352 d.sadd(beta,-1.,h);
00353 }
00354 }
00355 catch (...)
00356 {
00357 cleanup();
00358 throw;
00359 }
00360
00361
00362 if (do_eigenvalues)
00363 {
00364 ::TridiagonalMatrix<double> T(diagonal.size(), true);
00365 for (unsigned int i=0;i<diagonal.size();++i)
00366 {
00367 T(i,i) = diagonal[i];
00368 if (i< diagonal.size()-1)
00369 T(i,i+1) = offdiagonal[i];
00370 }
00371 T.compute_eigenvalues();
00372 if (additional_data.compute_condition_number
00373 && ! additional_data.compute_all_condition_numbers
00374 && (diagonal.size() > 1))
00375 ::deallog << "Condition number estimate: " <<
00376 T.eigenvalue(T.n()-1)/T.eigenvalue(0) << std::endl;
00377 if (additional_data.compute_eigenvalues)
00378 {
00379 for (unsigned int i=0;i<T.n();++i)
00380 ::deallog << ' ' << T.eigenvalue(i);
00381 ::deallog << std::endl;
00382 }
00383 }
00384
00385
00386 cleanup();
00387
00388
00389 if (this->control().last_check() != ::SolverControl::success)
00390 throw ::SolverControl::NoConvergence (this->control().last_step(),
00391 this->control().last_value());
00392
00393 }
00394
00395
00396 #endif // SOLVER_CG_H
00397