MFEM v2.0
|
00001 // Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at 00002 // the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights 00003 // reserved. See file COPYRIGHT for details. 00004 // 00005 // This file is part of the MFEM library. For more information and source code 00006 // availability see http://mfem.googlecode.com. 00007 // 00008 // MFEM is free software; you can redistribute it and/or modify it under the 00009 // terms of the GNU Lesser General Public License (as published by the Free 00010 // Software Foundation) version 2.1 dated February 1999. 00011 00012 #include <iostream> 00013 #include <iomanip> 00014 #include "vector.hpp" 00015 #include "matrix.hpp" 00016 00017 //***************************************************************** 00018 // Iterative template routine -- BiCGSTAB 00019 // 00020 // BiCGSTAB solves the unsymmetric linear system Ax = b 00021 // using the Preconditioned BiConjugate Gradient Stabilized method 00022 // 00023 // BiCGSTAB follows the algorithm described on p. 27 of the 00024 // SIAM Templates book. 00025 // 00026 // The return value indicates convergence within max_iter (input) 00027 // iterations (0), or no convergence within max_iter iterations (1). 00028 // 00029 // Upon successful return, output arguments have the following values: 00030 // 00031 // x -- approximate solution to Ax = b 00032 // max_iter -- the number of iterations performed before the 00033 // tolerance was reached 00034 // tol -- the residual after the final iteration 00035 // 00036 //***************************************************************** 00037 00038 int 00039 BiCGSTAB(const Operator &A, Vector &x, const Vector &b, 00040 const Operator &M, int &max_iter, double &tol, 00041 double atol, int printit) 00042 { 00043 int i, n = A.Size(); 00044 double resid; 00045 double rho_1, rho_2=1.0, alpha=1.0, beta, omega=1.0; 00046 Vector p(n), phat(n), s(n), shat(n), t(n), v(n), r(n), rtilde(n); 00047 00048 A.Mult (x, r); // r = A * x 00049 subtract (b, r, r); // r = b - r 00050 rtilde = r; 00051 00052 resid = (r * r); 00053 if (printit) 00054 cout << " iter " << 0 << ", (r, r) = " << resid << endl; 00055 tol *= resid; 00056 tol = (atol > tol) ? atol : tol; 00057 00058 if (resid <= tol) 00059 { 00060 tol = resid; 00061 max_iter = 0; 00062 return 0; 00063 } 00064 00065 for (i = 1; i <= max_iter; i++) 00066 { 00067 rho_1 = rtilde * r; 00068 if (rho_1 == 0) 00069 { 00070 tol = resid; 00071 if (printit) 00072 cout << " iter " << i << ", (r, r) = " << resid << endl; 00073 return 2; 00074 } 00075 if (i == 1) 00076 p = r; 00077 else 00078 { 00079 beta = (rho_1/rho_2) * (alpha/omega); 00080 add (p, -omega, v, p); // p = p - omega * v 00081 add (r, beta, p, p); // p = r + beta * p 00082 } 00083 M.Mult (p, phat); // phat = M^{-1} * p 00084 A.Mult (phat, v); // v = A * phat 00085 alpha = rho_1 / (rtilde * v); 00086 add (r, -alpha, v, s); // s = r - alpha * v 00087 resid = (s * s); 00088 if (resid < tol) 00089 { 00090 x.Add (alpha, phat); // x = x + alpha * phat 00091 tol = resid; 00092 if (printit) 00093 cout << " iter " << i << ", (s, s) = " << resid << endl; 00094 return 0; 00095 } 00096 if (printit) 00097 cout << " iter " << i << ", (s, s) = " << resid << "; "; 00098 M.Mult (s, shat); // shat = M^{-1} * s 00099 A.Mult (shat, t); // t = A * shat 00100 omega = (t * s) / (t * t); 00101 x.Add (alpha, phat); // x += alpha * phat 00102 x.Add (omega, shat); // x += omega * shat 00103 add (s, -omega, t, r); // r = s - omega * t 00104 00105 rho_2 = rho_1; 00106 resid = (r * r); 00107 if (printit) 00108 cout << "(r, r) = " << resid << endl; 00109 if (resid < tol) 00110 { 00111 tol = resid; 00112 max_iter = i; 00113 return 0; 00114 } 00115 if (omega == 0) 00116 { 00117 tol = resid; 00118 return 3; 00119 } 00120 } 00121 00122 tol = resid; 00123 return 1; 00124 }