AlgebraicMultigrid 0.1
C++ algebraic multigrid.
Loading...
Searching...
No Matches
smoother.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <string>
4
5#include <Eigen/Core>
6#include <Eigen/Sparse>
7
8#include <amg/common.hpp>
9
10namespace AMG {
11
18template <class EleType>
20 public:
25 EleType tolerance{1e-9};
26
32
37 size_t n_iters{1};
38
40
41 SmootherBase(size_t n_iters_) : n_iters(n_iters_) {}
42
50 SmootherBase(double tolerance_, size_t compute_error_every_n_iters_,
51 size_t n_iters_)
52 : tolerance(tolerance_),
53 compute_error_every_n_iters(compute_error_every_n_iters_),
54 n_iters(n_iters_) {}
55
63 virtual void smooth(const Eigen::SparseMatrix<EleType>& A,
64 Eigen::Matrix<EleType, -1, 1>& u,
65 const Eigen::Matrix<EleType, -1, 1>& b) = 0;
66};
67
86template <class EleType>
87class SparseGaussSeidel : public SmootherBase<EleType> {
88 private:
101 void matvecprod(int col, EleType& rsum, EleType& diag, const EleType& z,
102 const Eigen::SparseMatrix<EleType>& A,
103 const Eigen::Matrix<EleType, -1, 1>& u) {
104 int row;
105 EleType val;
106 for (typename Eigen::SparseMatrix<EleType>::InnerIterator it(A, col); it;
107 ++it) {
108 row = it.row();
109 val = it.value();
110 diag = (col == row) // if you found a value on the diagonal, update it for other iters
111 ? val
112 : diag; // column == row therefore val == A_ii on diag
113 rsum += (col == row)
114 ? z
115 : val * u[row]; // contrib to sum should be 0 for i==j by def
116 }
117 }
118
129 void update(int col, const Eigen::SparseMatrix<EleType>& A,
130 const Eigen::Matrix<EleType, -1, 1>& b,
131 Eigen::Matrix<EleType, -1, 1>& u) {
132 EleType z = 0;
133 EleType rsum = z;
134 EleType diag = z;
135 matvecprod(col, rsum, diag, z, A, u);
136 u[col] = diag == z ? u[col] : (b[col] - rsum) / diag;
137 return;
138 }
139
148 void forwardsweep(const Eigen::SparseMatrix<EleType>& A,
149 const Eigen::Matrix<EleType, -1, 1>& b,
150 Eigen::Matrix<EleType, -1, 1>& u, const int& ncols) {
151
152 // iterate through cols of A in forward direction
153 for (int col = 0; col < ncols; ++col) {
154 update(col, A, b, u);
155 }
156 return;
157 }
158
167 void backwardsweep(const Eigen::SparseMatrix<EleType>& A,
168 const Eigen::Matrix<EleType, -1, 1>& b,
169 Eigen::Matrix<EleType, -1, 1>& u, const int& ncols) {
170 // iterate through cols A in the backward direction
171 for (int col = ncols - 1; col >= 0; --col) {
172 update(col, A, b, u);
173 }
174 }
175
176 public:
177 using SmootherBase<EleType>::SmootherBase;
178
184 this->tolerance = 1e-9;
186 this->n_iters = 1;
187 }
188
189 void smooth(const Eigen::SparseMatrix<EleType>& A,
190 Eigen::Matrix<EleType, -1, 1>& u,
191 const Eigen::Matrix<EleType, -1, 1>& b) {
192 int ncols = A.cols();
193 size_t iter = 0;
194 EleType error = 100;
195 while (iter < this->n_iters && error > this->tolerance) {
196 forwardsweep(A, b, u, ncols);
197 backwardsweep(A, b, u, ncols);
198 iter += 1;
199 if (this->compute_error_every_n_iters != 0 &&
200 iter % this->compute_error_every_n_iters == 0) {
201 error = rss(A, u, b);
202 }
203 }
204
205 if (this->compute_error_every_n_iters != 0) {
206 if (error <= this->tolerance)
207 std::cout << "SPGS converged after " << iter << " iterations."
208 << std::endl;
209 else
210 std::cout << "SPGS did not converge after " << iter << " iterations."
211 << std::endl;
212 }
213
214 return;
215 }
216};
217
223template <class EleType>
224class Jacobi : public SmootherBase<EleType> {
225 public:
226 // C++11
227 // https://stackoverflow.com/questions/8093882/using-c-base-class-constructors
228 using SmootherBase<EleType>::SmootherBase;
229
231
239 void smooth(const Eigen::SparseMatrix<EleType>& A,
240 Eigen::Matrix<EleType, -1, 1>& u,
241 const Eigen::Matrix<EleType, -1, 1>& b) {
242 size_t iter = 0;
243 size_t ndofs = b.size();
244 EleType error = 100;
245 EleType sigma;
246 while (iter < this->n_iters && error > this->tolerance) {
247 for (size_t i = 0; i < ndofs; ++i) {
248 sigma = 0;
249 for (size_t j = 0; j < ndofs; ++j) {
250 if (j != i) {
251 sigma += A.coeff(i, j) * u[j];
252 }
253 }
254 EleType aii = A.coeff(i, i);
255 u[i] = (b[i] - sigma) / aii;
256 }
257 iter += 1;
258 if (iter % this->compute_error_every_n_iters == 0) {
259 error = rss(A, u, b);
260 }
261 }
262 return;
263 }
264};
265
271template <class EleType>
272class SuccessiveOverRelaxation : public SmootherBase<EleType> {
273 private:
278 double omega{1.0};
279
287 if (omega > 2 || omega < 0) {
288 std::string msg =
289 "`omega` must be in [0, 2] but got omega=" + std::to_string(omega) +
290 "\n";
291 throw std::invalid_argument(msg);
292 }
293 }
294
295 public:
296 // C++11
297 // https://stackoverflow.com/questions/8093882/using-c-base-class-constructors
298 using SmootherBase<EleType>::SmootherBase;
299
309 SuccessiveOverRelaxation(double omega_) : omega(omega_) { validate_omega(); }
310
321 SuccessiveOverRelaxation(double omega_, double tolerance_,
322 size_t compute_error_every_n_iters_, size_t n_iters_)
323 : SmootherBase<EleType>(tolerance_, compute_error_every_n_iters_,
324 n_iters_),
325 omega(omega_) {
327 }
328
339 void smooth(const Eigen::SparseMatrix<EleType>& A,
340 Eigen::Matrix<EleType, -1, 1>& u,
341 const Eigen::Matrix<EleType, -1, 1>& b) {
342 size_t iter = 0;
343 size_t ndofs = b.size();
344 EleType error = 100;
345 EleType sigma_j_less_i;
346 EleType sigma_j_greater_i;
347 while (iter < this->n_iters && error > this->tolerance) {
348 for (size_t i = 0; i < ndofs; ++i) {
349 sigma_j_less_i = 0;
350 for (size_t j = 0; j < i; ++j) {
351 sigma_j_less_i += A.coeff(i, j) * u[j];
352 }
353
354 sigma_j_greater_i = 0;
355 for (size_t j = i + 1; j < ndofs; ++j) {
356 sigma_j_greater_i += A.coeff(i, j) * u[j];
357 }
358
359 EleType aii = A.coeff(i, i);
360 EleType uk_plus_one_gauss_seidel =
361 (b[i] - sigma_j_less_i - sigma_j_greater_i) / aii;
362 EleType uk = u[i];
363
364 u[i] = uk + omega * (uk_plus_one_gauss_seidel - uk);
365 }
366 iter += 1;
367 if (iter % this->compute_error_every_n_iters == 0) {
368 error = rss(A, u, b);
369 }
370 }
371 return;
372 }
373};
374
375} // end namespace AMG
Dense Jacobi iterative method.
Definition smoother.hpp:224
void smooth(const Eigen::SparseMatrix< EleType > &A, Eigen::Matrix< EleType, -1, 1 > &u, const Eigen::Matrix< EleType, -1, 1 > &b)
Update initial guess u inplace using Jacobi method.
Definition smoother.hpp:239
Jacobi()
Definition smoother.hpp:230
Base class for smoothers that must implement a smooth function for the iterative solution of a linear...
Definition smoother.hpp:19
SmootherBase()
Definition smoother.hpp:39
EleType tolerance
Tolerance below which a smoother is considered to have converged.
Definition smoother.hpp:25
size_t n_iters
Maximum number of iterations before smoothing termination.
Definition smoother.hpp:37
virtual void smooth(const Eigen::SparseMatrix< EleType > &A, Eigen::Matrix< EleType, -1, 1 > &u, const Eigen::Matrix< EleType, -1, 1 > &b)=0
Must implement function that smooths Au = b.
size_t compute_error_every_n_iters
Compute the error every n iterations during smoothing.
Definition smoother.hpp:31
SmootherBase(double tolerance_, size_t compute_error_every_n_iters_, size_t n_iters_)
Construct a new Smoother Base object with iterative solver member data.
Definition smoother.hpp:50
SmootherBase(size_t n_iters_)
Definition smoother.hpp:41
Symmetric Gauss-Seidel smoother for sparse systems.
Definition smoother.hpp:87
SparseGaussSeidel()
Construct a new Sparse Gauss Seidel object for pre/post smoother in AMG.
Definition smoother.hpp:183
void backwardsweep(const Eigen::SparseMatrix< EleType > &A, const Eigen::Matrix< EleType, -1, 1 > &b, Eigen::Matrix< EleType, -1, 1 > &u, const int &ncols)
Gauss-Seidel iteration starting from the last row.
Definition smoother.hpp:167
void matvecprod(int col, EleType &rsum, EleType &diag, const EleType &z, const Eigen::SparseMatrix< EleType > &A, const Eigen::Matrix< EleType, -1, 1 > &u)
Modified sparse matvec product of Au for Gauss-Seidel sweeps.
Definition smoother.hpp:101
void smooth(const Eigen::SparseMatrix< EleType > &A, Eigen::Matrix< EleType, -1, 1 > &u, const Eigen::Matrix< EleType, -1, 1 > &b)
Must implement function that smooths Au = b.
Definition smoother.hpp:189
void update(int col, const Eigen::SparseMatrix< EleType > &A, const Eigen::Matrix< EleType, -1, 1 > &b, Eigen::Matrix< EleType, -1, 1 > &u)
Updates a single entry in u inplace using the definition of a Gauss-Seidel.
Definition smoother.hpp:129
void forwardsweep(const Eigen::SparseMatrix< EleType > &A, const Eigen::Matrix< EleType, -1, 1 > &b, Eigen::Matrix< EleType, -1, 1 > &u, const int &ncols)
Gauss-Seidel iteration starting from the first row.
Definition smoother.hpp:148
Dense successive over relaxation iterative method.
Definition smoother.hpp:272
SuccessiveOverRelaxation()
Definition smoother.hpp:300
void smooth(const Eigen::SparseMatrix< EleType > &A, Eigen::Matrix< EleType, -1, 1 > &u, const Eigen::Matrix< EleType, -1, 1 > &b)
Update initial guess u inplace with SOR and internal relaxation param omega
Definition smoother.hpp:339
double omega
Relaxation parameter in [0, 2].
Definition smoother.hpp:278
void validate_omega()
Force omega to be in [0, 2].
Definition smoother.hpp:286
SuccessiveOverRelaxation(double omega_)
Construct a new Successive Over Relaxation object.
Definition smoother.hpp:309
SuccessiveOverRelaxation(double omega_, double tolerance_, size_t compute_error_every_n_iters_, size_t n_iters_)
Construct a new Successive Over Relaxation object.
Definition smoother.hpp:321
Definition common.hpp:6
EleType rss(const Eigen::SparseMatrix< EleType > &A, const Eigen::Matrix< EleType, -1, 1 > &u, const Eigen::Matrix< EleType, -1, 1 > &b)
Return residual sum of squares of bhat from Au and rhs b.
Definition common.hpp:18