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 <fstream> 00014 #include <iomanip> 00015 #include <math.h> 00016 #include "vector.hpp" 00017 #include "matrix.hpp" 00018 #include "sparsemat.hpp" 00019 00020 // Preconditined conjugate gradient 00021 00022 void PCG ( const Operator &A, const Operator &B, 00023 const Vector &b, Vector &x, 00024 int print_iter=0, int max_num_iter=1000, 00025 double RTOLERANCE=10e-12, double ATOLERANCE=10e-24, 00026 int save = 0) 00027 { 00028 int i, dim = x.Size(); 00029 double r0, den, nom, nom0, betanom, alpha, beta; 00030 Vector r(dim), d(dim), z(dim); 00031 00032 A.Mult(x, r); // r = A x 00033 subtract(b, r, r); // r = b - r 00034 B.Mult(r, z); // z = B r 00035 d = z; 00036 nom0 = nom = z * r; 00037 00038 if (print_iter == 1) 00039 cout << " Iteration : " << setw(3) << 0 << " (B r, r) = " 00040 << nom << endl; 00041 00042 if ( (r0 = nom * RTOLERANCE) < ATOLERANCE) r0 = ATOLERANCE; 00043 if (nom < r0) 00044 return; 00045 00046 A.Mult(d, z); 00047 den = z * d; 00048 00049 if (den < 0.0) 00050 { 00051 cout << "Negative denominator in step 0 of PCG: "; 00052 cout << den << endl; 00053 // return; 00054 } 00055 00056 if (den == 0.0) 00057 return; 00058 00059 // start iteration 00060 for (i = 1; i <= max_num_iter; i++) 00061 { 00062 if (save) 00063 if (i % save == 0) 00064 { 00065 cout << "saving the solution vector on iteration " << i << endl; 00066 ofstream out("pcg.x"); 00067 x.Print(out, 1); 00068 } 00069 00070 alpha = nom/den; 00071 add(x, alpha, d, x); // x = x + alpha d 00072 add(r,-alpha, z, r); // r = r - alpha z 00073 00074 B.Mult(r, z); // z = B r 00075 betanom = r * z; 00076 00077 if (print_iter == 1) 00078 cout << " Iteration : " << setw(3) << i << " (B r, r) = " 00079 << betanom << endl; 00080 00081 if (betanom < r0) 00082 { 00083 if (print_iter == 2) 00084 cout << "Number of PCG iterations: " << i << endl; 00085 else 00086 if (print_iter == 3) 00087 cout << "(B r_0, r_0) = " << nom0 << endl 00088 << "(B r_N, r_N) = " << betanom << endl 00089 << "Number of PCG iterations: " << i << endl; 00090 break; 00091 } 00092 00093 beta = betanom/nom; 00094 add(z, beta, d, d); // d = z + beta d 00095 A.Mult(d, z); 00096 den = d * z; 00097 nom = betanom; 00098 } 00099 if (i > max_num_iter) 00100 { 00101 cerr << "PCG: No convergence!" << endl; 00102 cout << "(B r_0, r_0) = " << nom0 << endl 00103 << "(B r_N, r_N) = " << betanom << endl 00104 << "Number of PCG iterations: " << (i-1) << endl; 00105 } 00106 if (print_iter >= 1 || i > max_num_iter) 00107 { 00108 if (i > max_num_iter) i--; 00109 cout << "Average reduction factor = " 00110 << pow (betanom/nom0, 0.5/i) << endl; 00111 } 00112 } 00113 00114 // Preconditioned stationary linear iteration 00115 void SLI (const Operator &A, const Operator &B, 00116 const Vector &b, Vector &x, 00117 int print_iter=0, int max_num_iter=1000, 00118 double RTOLERANCE=10e-12, double ATOLERANCE=10e-24) 00119 { 00120 int i, dim = x.Size(); 00121 double r0, nom, nomold = 1, nom0, cf; 00122 Vector r(dim), z(dim); 00123 00124 r0 = -1.0; 00125 00126 for(i = 1; i < max_num_iter ; i++) { 00127 A.Mult(x, r); // r = A x 00128 subtract(b, r, r); // r = b - A x 00129 B.Mult(r, z); // z = B r 00130 00131 nom = z * r; 00132 00133 if (r0 == -1.0) { 00134 nom0 = nom; 00135 r0 = nom * RTOLERANCE; 00136 if (r0 < ATOLERANCE) r0 = ATOLERANCE; 00137 } 00138 00139 cf = sqrt(nom/nomold); 00140 if (print_iter == 1) { 00141 cout << " Iteration : " << setw(3) << i << " (B r, r) = " 00142 << nom; 00143 if (i > 1) 00144 cout << "\tConv. rate: " << cf; 00145 cout << endl; 00146 } 00147 nomold = nom; 00148 00149 if (nom < r0) { 00150 if (print_iter == 2) 00151 cout << "Number of iterations: " << i << endl 00152 << "Conv. rate: " << cf << endl; 00153 else 00154 if (print_iter == 3) 00155 cout << "(B r_0, r_0) = " << nom0 << endl 00156 << "(B r_N, r_N) = " << nom << endl 00157 << "Number of iterations: " << i << endl; 00158 break; 00159 } 00160 00161 add(x, 1.0, z, x); // x = x + B (b - A x) 00162 } 00163 00164 if (i == max_num_iter) 00165 { 00166 cerr << "No convergence!" << endl; 00167 cout << "(B r_0, r_0) = " << nom0 << endl 00168 << "(B r_N, r_N) = " << nom << endl 00169 << "Number of iterations: " << i << endl; 00170 } 00171 }