Skip to content

Commit 158f0dd

Browse files
committed
iteration limit and error reporting for CG solve
1 parent 8935f6c commit 158f0dd

File tree

1 file changed

+31
-6
lines changed

1 file changed

+31
-6
lines changed

p3a_cg.hpp

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,21 @@
11
#pragma once
22

33
#include <stdexcept>
4+
#include <string>
45

56
#include "p3a_dynamic_array.hpp"
67
#include "p3a_reduce.hpp"
78

89
namespace p3a {
910

11+
class convergence_failure : public std::runtime_error {
12+
public:
13+
convergence_failure(std::string const& msg)
14+
:std::runtime_error(msg)
15+
{
16+
}
17+
};
18+
1019
template <
1120
class T,
1221
class Allocator = host_allocator<T>,
@@ -20,6 +29,8 @@ class preconditioned_conjugate_gradient {
2029
array_type m_p;
2130
array_type m_scratch;
2231
associative_sum<T, Allocator, ExecutionPolicy> m_adder;
32+
T m_relative_tolerance = 1.0e-6;
33+
int m_maximum_iterations = 1'000'000;
2334
public:
2435
using M_inv_action_type = std::function<
2536
void(array_type const&, array_type&)>;
@@ -31,12 +42,19 @@ class preconditioned_conjugate_gradient {
3142
preconditioned_conjugate_gradient(mpicpp::comm&& comm_arg)
3243
:m_adder(std::move(comm_arg))
3344
{}
45+
void set_relative_tolerance(T const& arg)
46+
{
47+
m_relative_tolerance = arg;
48+
}
49+
void set_maximum_iterations(int arg)
50+
{
51+
m_maximum_iterations = arg;
52+
}
3453
P3A_NEVER_INLINE int solve(
3554
M_inv_action_type const& M_inv_action,
3655
A_action_type const& A_action,
3756
b_filler_type const& b_filler,
38-
array_type& x,
39-
T const& relative_tolerance);
57+
array_type& x);
4058
};
4159

4260
template <
@@ -90,8 +108,7 @@ int preconditioned_conjugate_gradient<T, Allocator, ExecutionPolicy>::solve(
90108
M_inv_action_type const& M_inv_action,
91109
A_action_type const& A_action,
92110
b_filler_type const& b_filler,
93-
array_type& x,
94-
T const& relative_tolerance)
111+
array_type& x)
95112
{
96113
this->m_r.resize(x.size());
97114
this->m_z.resize(x.size());
@@ -107,9 +124,9 @@ int preconditioned_conjugate_gradient<T, Allocator, ExecutionPolicy>::solve(
107124
T const b_dot_b = dot_product(m_adder, b, b);
108125
T const b_magnitude = p3a::sqrt(b_dot_b);
109126
if (b_magnitude == T(0)) {
110-
throw std::runtime_error("p3a::preconditioned_conjugate_gradient: b_magnitude = 0");
127+
throw std::invalid_argument("P3A CG solver: the magnitude of the right hand side vector is zero");
111128
}
112-
T const absolute_tolerance = b_magnitude * relative_tolerance;
129+
T const absolute_tolerance = b_magnitude * m_relative_tolerance;
113130
A_action(x, Ax); // Ax = A * x
114131
axpy(T(-1), Ax, b, r); // r = A * x - b
115132
T residual_magnitude = p3a::sqrt(dot_product(m_adder, r, r));
@@ -127,6 +144,14 @@ int preconditioned_conjugate_gradient<T, Allocator, ExecutionPolicy>::solve(
127144
if (residual_magnitude <= absolute_tolerance) {
128145
return k;
129146
}
147+
if (k == m_maximum_iterations) {
148+
throw convergence_failure(
149+
"P3A CG solver failed to converge in " + std::to_string(m_maximum_iterations) +
150+
" iterations. relative tolerance was " + std::to_string(m_relative_tolerance) +
151+
", right hand side magnitude was " + std::to_string(b_magnitude) +
152+
", absolute_tolerance was " + std::to_string(absolute_tolerance) +
153+
", and final residual magnitude was " + std::to_string(residual_magnitude));
154+
}
130155
M_inv_action(r, z); // z = M^-1 r
131156
T const r_dot_z_new = dot_product(m_adder, r, z);
132157
T const beta = r_dot_z_new / r_dot_z_old;

0 commit comments

Comments
 (0)