namespace SpaMtrix IterativeSolvers IterativeSolvers maxIter maxInnerI

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
namespace SpaMtrix {
IterativeSolvers::IterativeSolvers():
maxIter(0),
maxInnerIter(0),
toler(0) {
}
IterativeSolvers::IterativeSolvers(const idx maxIter,
const real toler):
maxIter(maxIter),
maxInnerIter(0),
toler(toler) {
}
IterativeSolvers::IterativeSolvers(const idx maxIter,
const idx maxInnerIter,
const real toler):
maxIter(maxIter),
maxInnerIter(maxInnerIter),
toler(toler) {
}
bool IterativeSolvers::pcg(const IRCMatrix &A,
Vector &x,
const Vector &b,
const Preconditioner &M) {
/*!
Solves Ax=b using the preconditioned conjugate gradient method.
*/
const idx N = x.getLength();
real resid(100.0);
Vector p(N), z(N), q(N);
real alpha;
real normr(0);
real normb = norm(b);
real rho(0), rho_1(0), beta(0);
Vector r = b - A * x;
if (normb == 0.0)
normb = 1;
resid = norm(r) / normb;
if (resid <= IterativeSolvers::toler) {
IterativeSolvers::toler = resid;
IterativeSolvers::maxIter = 0;
return true;
}
// MAIN LOOP
idx i = 1;
for (; i <= IterativeSolvers::maxIter; i++) {
M.solveMxb(z, r);
rho = dot(r, z);
if (i == 1)
p = z;
else {
beta = rho / rho_1;
aypx(beta, p, z); // p = beta*p + z;
}
// CALCULATES q = A*p AND dp = dot(q,p)
real dp = multiply_dot(A, p, q);
alpha = rho / dp;
normr = 0;
#ifdef USES_OPENMP
#pragma omp parallel for reduction(+:normr)
#endif
for (idx j = 0 ; j < N ; ++j) {
x[j] += alpha * p[j]; // x + alpha(0) * p;
r[j] -= alpha * q[j]; // r - alpha(0) * q;
normr += r[j] * r[j];
}
normr = sqrt(normr);
resid = normr / normb;
if (resid <= IterativeSolvers::toler) {
IterativeSolvers::toler = resid;
IterativeSolvers::maxIter = i;
return true;
}
rho_1 = rho;
}
IterativeSolvers::toler = resid;
return false;
}