00001 #ifdef CH_LANG_CC
00002
00003
00004
00005
00006
00007
00008
00009 #endif
00010
00011
00012
00013 #ifndef _BICGSTABSOLVER_H_
00014 #define _BICGSTABSOLVER_H_
00015
00016 #include "LinearSolver.H"
00017 #include "parstream.H"
00018 #include "CH_Timer.H"
00019 #include "NamespaceHeader.H"
00020
00021
00022
00023
00024
00025 template <class T>
00026 class BiCGStabSolver : public LinearSolver<T>
00027 {
00028 public:
00029
00030 BiCGStabSolver();
00031
00032 virtual ~BiCGStabSolver();
00033
00034 virtual void setHomogeneous(bool a_homogeneous)
00035 {
00036 m_homogeneous = a_homogeneous;
00037 }
00038
00039
00040
00041
00042
00043
00044
00045 virtual void define(LinearOp<T>* a_op, bool a_homogeneous);
00046
00047
00048 virtual void solve(T& a_phi, const T& a_rhs);
00049
00050
00051 virtual void setConvergenceMetrics(Real a_metric,
00052 Real a_tolerance);
00053
00054
00055
00056
00057
00058
00059 bool m_homogeneous;
00060
00061
00062
00063
00064
00065 LinearOp<T>* m_op;
00066
00067
00068
00069
00070
00071 int m_imax;
00072
00073
00074
00075
00076
00077
00078 int m_verbosity;
00079
00080
00081
00082
00083
00084 Real m_eps;
00085
00086
00087
00088
00089
00090 Real m_reps;
00091
00092
00093
00094
00095
00096
00097 Real m_convergenceMetric;
00098
00099
00100
00101
00102
00103 Real m_hang;
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113 int m_exitStatus;
00114
00115
00116
00117
00118
00119 Real m_small;
00120
00121
00122
00123
00124
00125 int m_numRestarts;
00126
00127
00128
00129
00130
00131
00132 int m_normType;
00133
00134 };
00135
00136
00137
00138
00139
00140
00141
00142 template <class T>
00143 BiCGStabSolver<T>::BiCGStabSolver()
00144 :m_homogeneous(false),
00145 m_op(NULL),
00146 m_imax(80),
00147 m_verbosity(3),
00148 m_eps(1.0E-6),
00149 m_reps(1.0E-12),
00150 m_convergenceMetric(-1.0),
00151 m_hang(1E-8),
00152 m_exitStatus(-1),
00153 m_small(1.0E-30),
00154 m_numRestarts(5),
00155 m_normType(2)
00156 {
00157 }
00158
00159 template <class T>
00160 BiCGStabSolver<T>::~BiCGStabSolver()
00161 {
00162 m_op = NULL;
00163 }
00164
00165 template <class T>
00166 void BiCGStabSolver<T>::define(LinearOp<T>* a_operator, bool a_homogeneous)
00167 {
00168 m_homogeneous = a_homogeneous;
00169 m_op = a_operator;
00170 }
00171
00172 template <class T>
00173 void BiCGStabSolver<T>::solve(T& a_phi, const T& a_rhs)
00174 {
00175 CH_TIMERS("BiCGStabSolver::solve");
00176
00177 CH_TIMER("BiCGStabSolver::solve::Initialize",timeInitialize);
00178 CH_TIMER("BiCGStabSolver::solve::MainLoop",timeMainLoop);
00179 CH_TIMER("BiCGStabSolver::solve::Cleanup",timeCleanup);
00180
00181 CH_START(timeInitialize);
00182
00183 T r, r_tilde, e, p, p_tilde, s_tilde, t, v;
00184
00185 m_op->create(r, a_rhs);
00186 m_op->create(r_tilde, a_rhs);
00187 m_op->create(e, a_phi);
00188 m_op->create(p, a_rhs);
00189 m_op->create(p_tilde, a_phi);
00190 m_op->create(s_tilde, a_phi);
00191 m_op->create(t, a_rhs);
00192 m_op->create(v, a_rhs);
00193
00194 int recount = 0;
00195
00196 CH_assert(m_op != NULL);
00197 m_op->setToZero(r);
00198
00199 m_op->residual(r, a_phi, a_rhs, m_homogeneous);
00200
00201 m_op->assignLocal(r_tilde, r);
00202 m_op->setToZero(e);
00203
00204
00205 m_op->setToZero(p_tilde);
00206 m_op->setToZero(s_tilde);
00207
00208 int i = 0;
00209
00210
00211 Real rho[4]=
00212 {
00213 0,0,0,0
00214 };
00215 Real norm[2];
00216 norm[0] = m_op->norm(r, m_normType);
00217 Real initial_norm = norm[0];
00218 Real initial_rnorm = norm[0];
00219 norm[1] = norm[0];
00220
00221 Real alpha[2] =
00222 {
00223 0,0
00224 };
00225 Real beta[2] =
00226 {
00227 0,0
00228 };
00229 Real omega[2] =
00230 {
00231 0,0
00232 };
00233
00234 bool init = true;
00235 int restarts = 0;
00236
00237 if (m_verbosity >= 5)
00238 {
00239 pout() << " BiCGStab:: initial Residual norm = "
00240 << initial_norm << "\n";
00241 }
00242
00243
00244
00245 if (m_convergenceMetric > 0)
00246 {
00247 initial_norm = m_convergenceMetric;
00248 }
00249
00250 CH_STOP(timeInitialize);
00251
00252 CH_START(timeMainLoop);
00253 while ((i<m_imax && norm[0] > m_eps*norm[1]) && (norm[1] > 0))
00254 {
00255 i++;
00256
00257 norm[1] = norm[0];
00258 alpha[1]= alpha[0];
00259 beta[1] = beta[0];
00260 omega[1]= omega[0];
00261
00262 if (m_verbosity >= 5)
00263 {
00264 pout() << " BiCGStab:: norm[0] = " << norm[0] << ", "
00265 << "norm[1] = " << norm[1]
00266 << "\n";
00267 pout() << " BiCGStab:: alpha[0] = " << alpha[0] << ", "
00268 << "alpha[1] = " << alpha[1]
00269 << "\n";
00270 pout() << " BiCGStab:: beta[0] = " << beta[0] << ", "
00271 << "beta[1] = " << beta[1]
00272 << "\n";
00273 pout() << " BiCGStab:: omega[0] = " << omega[0] << ", "
00274 << "omega[1] = " << omega[1]
00275 << "\n";
00276 }
00277
00278 rho[3] = rho[2];
00279 rho[2] = rho[1];
00280 rho[1] = m_op->dotProduct(r_tilde, r);
00281
00282 if (m_verbosity >= 5)
00283 {
00284 pout() << " BiCGStab:: rho[1] = " << rho[1] << ", "
00285 << "rho[2] = " << rho[2] << ", "
00286 << "rho[3] = " << rho[3]
00287 << "\n";
00288 }
00289
00290 if (rho[1] == 0.0)
00291 {
00292
00293 m_op->incr(a_phi, e, 1.0);
00294
00295 if (m_verbosity >= 5)
00296 {
00297 pout() << " BiCGStab:: rho = 0, returning"
00298 << " -- Residual norm = "
00299 << norm[0] << "\n";
00300 }
00301
00302 CH_STOP(timeMainLoop);
00303
00304 CH_START(timeCleanup);
00305
00306 m_exitStatus = 2;
00307
00308
00309
00310 m_op->clear(r);
00311 m_op->clear(r_tilde);
00312 m_op->clear(e);
00313 m_op->clear(p);
00314 m_op->clear(p_tilde);
00315 m_op->clear(s_tilde);
00316 m_op->clear(t);
00317 m_op->clear(v);
00318
00319 CH_STOP(timeCleanup);
00320
00321 return;
00322 }
00323
00324 if (init)
00325 {
00326 m_op->assignLocal(p, r);
00327 init = false;
00328 }
00329 else
00330 {
00331 beta[1] = (rho[1]/rho[2])*(alpha[1]/omega[1]);
00332 m_op->scale(p, beta[1]);
00333 m_op->incr(p, v, -beta[1]*omega[1]);
00334 m_op->incr(p, r, 1.0);
00335 }
00336
00337 if (m_verbosity >= 5)
00338 {
00339 pout() << " BiCGStab:: beta[1] = " << beta[1]
00340 << "\n";
00341 }
00342
00343 m_op->preCond(p_tilde, p);
00344 m_op->setToZero(v);
00345 m_op->applyOp(v, p_tilde, true);
00346 Real m = m_op->dotProduct(r_tilde, v);
00347 alpha[0] = rho[1]/m;
00348
00349 if (m_verbosity >= 5)
00350 {
00351 pout() << " BiCGStab:: rho[1] = " << rho[1] << ", "
00352 << "m = " << m << ", "
00353 << "alpha[0] = " << alpha[0]
00354 << "\n";
00355 }
00356
00357 if (Abs(m) > m_small*Abs(rho[1]))
00358 {
00359 m_op->incr(r, v, -alpha[0]);
00360 norm[0] = m_op->norm(r, m_normType);
00361 m_op->incr(e, p_tilde, alpha[0]);
00362 }
00363 else
00364 {
00365 m_op->setToZero(r);
00366 norm[0] = 0.0;
00367 }
00368
00369 if (m_verbosity >= 4)
00370 {
00371 pout() << "norm[0] = " << norm[0]
00372 << " initial_norm = " << initial_norm
00373 << " initial_rnorm = " << initial_rnorm << endl;
00374 }
00375
00376 if (norm[0] > m_eps*initial_norm && norm[0] > m_reps*initial_rnorm)
00377 {
00378 m_op->preCond(s_tilde, r);
00379 m_op->setToZero(t);
00380 m_op->applyOp(t, s_tilde, true);
00381 omega[0] = m_op->dotProduct(t, r)/m_op->dotProduct(t, t);
00382 m_op->incr(e, s_tilde, omega[0]);
00383 m_op->incr(r, t, -omega[0]);
00384 norm[0] = m_op->norm(r, m_normType);
00385 }
00386
00387 if (m_verbosity >= 4)
00388 {
00389 pout() << " BiCGStab:: iteration = " << i << ", error norm = " << norm[0] << ", rate = " << norm[1]/norm[0] << "\n";
00390 }
00391
00392 if (norm[0] <= m_eps*initial_norm || norm[0] <= m_reps*initial_rnorm)
00393 {
00394
00395 m_exitStatus = 1;
00396 break;
00397 }
00398
00399 if (omega[0] == 0.0 || norm[0] > (1-m_hang)*norm[1])
00400 {
00401 if (recount == 0)
00402 {
00403 recount = 1;
00404 }
00405 else
00406 {
00407 recount = 0;
00408 m_op->incr(a_phi, e, 1.0);
00409
00410 if (restarts == m_numRestarts)
00411 {
00412 if (m_verbosity >= 4)
00413 {
00414 pout() << " BiCGStab: max restarts reached" << endl;
00415 pout() << " init norm = " << initial_norm << endl;
00416 pout() << " final norm = " << norm[0] << endl;
00417 }
00418
00419 CH_STOP(timeMainLoop);
00420
00421 CH_START(timeCleanup);
00422
00423 m_exitStatus = 3;
00424
00425
00426
00427
00428 m_op->clear(r);
00429 m_op->clear(r_tilde);
00430 m_op->clear(e);
00431 m_op->clear(p);
00432 m_op->clear(p_tilde);
00433 m_op->clear(s_tilde);
00434 m_op->clear(t);
00435 m_op->clear(v);
00436
00437 CH_STOP(timeCleanup);
00438
00439 return;
00440 }
00441
00442 {
00443 CH_TIME("BiCGStabSolver::solve::Restart");
00444
00445 m_op->residual(r, a_phi, a_rhs, m_homogeneous);
00446 norm[0] = m_op->norm(r, m_normType);
00447 rho[1]=0.0; rho[1]=0.0; rho[2]=0.0; rho[3]=0.0;
00448 alpha[0]=0; beta[0]=0; omega[0]=0;
00449 m_op->assignLocal(r_tilde, r);
00450 m_op->setToZero(e);
00451
00452 restarts++;
00453 }
00454
00455 if (m_verbosity >= 4)
00456 {
00457 pout() << " BiCGStab:: restart = " << restarts << "\n";
00458 }
00459
00460 init = true;
00461 }
00462 }
00463 }
00464 CH_STOP(timeMainLoop);
00465
00466 CH_START(timeCleanup);
00467
00468 if (m_verbosity >= 4)
00469 {
00470 pout() << " BiCGStab:: " << i << " iterations, final Residual norm = "
00471 << norm[0] << "\n";
00472 }
00473
00474 m_op->incr(a_phi, e, 1.0);
00475
00476 m_op->clear(r);
00477 m_op->clear(r_tilde);
00478 m_op->clear(e);
00479 m_op->clear(p);
00480 m_op->clear(p_tilde);
00481 m_op->clear(s_tilde);
00482 m_op->clear(t);
00483 m_op->clear(v);
00484
00485 CH_STOP(timeCleanup);
00486 }
00487
00488 template <class T>
00489 void BiCGStabSolver<T>::setConvergenceMetrics(Real a_metric,
00490 Real a_tolerance)
00491 {
00492 m_convergenceMetric = a_metric;
00493 m_eps = a_tolerance;
00494 }
00495
00496 #include "NamespaceFooter.H"
00497 #endif