AlgebraicMultigrid 0.1
C++ algebraic multigrid.
Loading...
Searching...
No Matches
multigrid.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <vector>
4
5#include <Eigen/Core>
6#include <Eigen/Sparse>
7#include <Eigen/SparseCholesky>
8
9#include <amg/common.hpp>
10#include <amg/grid.hpp>
11#include <amg/interpolator.hpp>
12#include <amg/smoother.hpp>
13
14namespace AMG {
15
22template <class EleType>
23class Multigrid {
24 private:
30
32
33 Eigen::SimplicialLDLT<Eigen::SparseMatrix<EleType>> coarse_direct_solver;
34
39 EleType tolerance;
40
46
51 size_t n_iters;
52
58
63 size_t n_levels;
64
69 size_t finest_grid_ix = 0;
70
76
83 std::vector<size_t> level_to_n_dofs;
84
89 std::vector<Eigen::SparseMatrix<EleType>> level_to_coefficient_matrix;
90
95 std::vector<Eigen::Matrix<EleType, -1, 1>> level_to_rhs;
96
101 std::vector<Eigen::Matrix<EleType, -1, 1>> level_to_soln;
102
107 std::vector<Eigen::Matrix<EleType, -1, 1>> level_to_residual;
108
127 size_t n_H_dofs_from_n_h_dofs(size_t h_dofs) {
128 size_t H_dofs = (h_dofs + 1) / 2 - 1;
129 return H_dofs;
130 }
131
132 bool display_error{false};
133
134 public:
136
137 Multigrid() = delete;
138
153 const Eigen::SparseMatrix<EleType>& A,
154 const Eigen::Matrix<EleType, -1, 1>& b, size_t n_levels_,
155 EleType tolerance_ = 1e-9, size_t compute_error_every_n_iters_ = 10,
156 size_t n_iters_ = 100)
157 : interpolator(interpolator_),
158 smoother(smoother_),
159 n_levels(n_levels_),
160 tolerance(tolerance_),
161 compute_error_every_n_iters(compute_error_every_n_iters_),
162 n_iters(n_iters_) {
163
164 std::string errormsg;
166 errormsg =
167 "`compute_error_every_n_iters` must be leq to `n_iters`, got " +
168 std::to_string(compute_error_every_n_iters) + " and " +
169 std::to_string(n_iters);
170 throw(std::invalid_argument(errormsg));
171 }
172
173 if (A.rows() != b.rows()) {
174 errormsg =
175 "`A` and `b` must have the same number of degrees of freedom, got " +
176 std::to_string(A.rows()) + " and " + std::to_string(b.rows());
177 throw(std::invalid_argument(errormsg));
178 }
179
180 // Initialize linear system info
182 level_to_soln.resize(n_levels);
183 level_to_rhs.resize(n_levels);
186
187 // Initialize index for coarsest grid
189
190 // Initialize the finest coefficients matrix
191 size_t n_fine_dofs = A.rows();
192 level_to_n_dofs[finest_grid_ix] = n_fine_dofs;
194
195 // Initialize the finest solutions vector
196 Eigen::Matrix<EleType, -1, 1> u(n_fine_dofs);
197 u.setZero();
199
200 // Initialize the finest right hand side
202
203 // Initialize the finest residual
205
206 // Use the finest level grid info to construct the linear interpolators
207 // needed to construct the remaining grid stuff
208 // TODO: could do while coarsest is greater than max coarse ndofs
209 size_t n_H_dofs;
210 size_t n_h_dofs;
211 for (size_t level = 1; level < n_levels; ++level) {
212 // Make restriction/prolongation matrices
213 n_h_dofs = level_to_n_dofs[level - 1];
214 n_H_dofs = n_H_dofs_from_n_h_dofs(n_h_dofs);
215 level_to_n_dofs[level] = n_H_dofs;
216 interpolator->make_operators(n_h_dofs, n_H_dofs, level - 1);
217
218 // Make coefficient matrix using interpolation operators
219 auto R_h = interpolator->get_R(level - 1);
220 auto A_h = level_to_coefficient_matrix[level - 1]; // finer matrix
221 auto P_h = interpolator->get_P(level - 1);
222 auto A_H = R_h * (A_h * P_h); // coarser matrix
223 level_to_coefficient_matrix[level] = A_H;
224
225 // Make solution vector
226 Eigen::Matrix<EleType, -1, 1> u_H(n_H_dofs);
227 u_H.setZero();
228 level_to_soln[level] = u_H;
229
230 // Make right hand side
231 Eigen::Matrix<EleType, -1, 1> rhs_H(n_H_dofs);
232 rhs_H.setZero();
233 level_to_rhs[level] = rhs_H;
234
235 // Make residual vector
236 level_to_residual[level] = rhs_H - A_H * u_H;
237 }
238
239 // Initialize the coarse solver
240 coarse_direct_solver.analyzePattern(
242 coarse_direct_solver.factorize(
244 }
245
263 void vcycle() {
264 // At each level of the grid hiearchy, finest-to-coarsest:
265 for (size_t level = 0; level < n_levels; ++level) {
266 // 1. Apply a couple of smoothing iterations (pre-relaxation) to the
267 // current solution ui=Si(Ai,fi,ui)
269 level_to_rhs[level]);
270
271 // 2. Find residual ei=fi−Aiui and restrict it to the coarser level
272 level_to_residual[level] =
273 level_to_rhs[level] -
275
276 if (level + 1 != n_levels) {
277 // initialize coarse solution to zero here refs [2-4].
278 level_to_soln[level + 1].setZero();
279
280 // f_{i+1} = R_{i} e_{i}
281 level_to_rhs[level + 1] =
282 interpolator->restriction(level_to_residual[level], level);
283 }
284 }
285
286 // Solve the coarsest system directly: uL=A−1LfL
289
290 // At each level of the grid hierarchy, coarsest-to-finest:
291 for (int level = coarsest_grid_ix - 1; level >= 0; --level) {
292 // 1. Update the current solution with the interpolated solution from the
293 // coarser level: ui=ui+Piui+1
294 level_to_soln[level] =
295 level_to_soln[level] +
296 interpolator->prolongation(level_to_soln[level + 1], level);
297
298 // 2. Apply a couple of smoothing iterations (post-relaxation) to the
299 // updated solution: ui=Si(Ai,fi,ui)
301 level_to_rhs[level]);
302 }
303
304 return;
305 }
306
311 const Eigen::Matrix<EleType, -1, 1>& solve() {
312 size_t iter = 0;
313 EleType error = 100;
315 auto b = get_rhs(finest_grid_ix);
316 while (iter < n_iters && error > tolerance) {
317 vcycle();
318 iter += 1;
319 if ((iter % compute_error_every_n_iters) == 0) {
320 auto u = get_soln(finest_grid_ix);
321 error = rss(A, u, b);
322
323 if (display_error) {
324 std::cout << "Iter: " << iter << " | Error: " << error << std::endl;
325 }
326 }
327 }
328
329 if (error <= tolerance)
330 std::cout << "AMG converged after " << iter << " iterations."
331 << std::endl;
332 else
333 std::cout << "AMG did not converge after " << iter << " iterations."
334 << std::endl;
335
337 }
338
339 const Eigen::SparseMatrix<EleType>& get_coefficient_matrix(
340 size_t level) const {
341 return level_to_coefficient_matrix[level];
342 }
343
344 const Eigen::Matrix<EleType, -1, 1>& get_soln(size_t level) const {
345 return level_to_soln[level];
346 }
347
348 const Eigen::Matrix<EleType, -1, 1>& get_rhs(size_t level) const {
349 return level_to_rhs[level];
350 }
351
352 const size_t get_n_dofs(size_t level) const { return level_to_n_dofs[level]; }
353
354 const EleType get_tolerance() const { return tolerance; }
355
357 display_error = true;
358 return;
359 }
360
362 display_error = true;
363 return;
364 }
365};
366
367} // end namespace AMG
Base class for interpolators that implement prolongation and restriction as linear operators construc...
Definition interpolator.hpp:16
Interface for multigrid solver (via solve) that iteratively performs standard vcycles.
Definition multigrid.hpp:23
const EleType get_tolerance() const
Definition multigrid.hpp:354
const Eigen::Matrix< EleType, -1, 1 > & get_soln(size_t level) const
Definition multigrid.hpp:344
AMG::SmootherBase< EleType > * smoother
Definition multigrid.hpp:31
void display_error_on()
Definition multigrid.hpp:356
size_t n_levels
Number of multigrid levels where level 0 is finest.
Definition multigrid.hpp:63
size_t compute_error_every_n_iters
Compute the error every n iterations during smoothing.
Definition multigrid.hpp:45
void vcycle()
A single multigrid vcycle.
Definition multigrid.hpp:263
const Eigen::Matrix< EleType, -1, 1 > & get_rhs(size_t level) const
Definition multigrid.hpp:348
Eigen::SimplicialLDLT< Eigen::SparseMatrix< EleType > > coarse_direct_solver
Definition multigrid.hpp:33
size_t finest_grid_ix
Index of the finest grid.
Definition multigrid.hpp:69
std::vector< Eigen::Matrix< EleType, -1, 1 > > level_to_rhs
Map multigrid level to right hand side (forcing) vector.
Definition multigrid.hpp:95
const Eigen::Matrix< EleType, -1, 1 > & solve()
Solve a linear system of equations via vcycle.
Definition multigrid.hpp:311
bool display_error
Definition multigrid.hpp:132
const Eigen::SparseMatrix< EleType > & get_coefficient_matrix(size_t level) const
Definition multigrid.hpp:339
size_t n_fine_nodes
Definition multigrid.hpp:57
~Multigrid()
Definition multigrid.hpp:135
size_t n_iters
Maximum number of iterations before smoothing termination.
Definition multigrid.hpp:51
Multigrid()=delete
InterpolatorBase< EleType > * interpolator
Interpolator providing restriction and prolongation operations.
Definition multigrid.hpp:29
size_t n_H_dofs_from_n_h_dofs(size_t h_dofs)
Return number of next coarsest dofs given finer dofs.
Definition multigrid.hpp:127
EleType tolerance
Tolerance below which a smoother is considered to have converged.
Definition multigrid.hpp:39
std::vector< Eigen::Matrix< EleType, -1, 1 > > level_to_residual
Map multigrid level to residual (e) vector.
Definition multigrid.hpp:107
size_t coarsest_grid_ix
Index of the coarsest grid.
Definition multigrid.hpp:75
std::vector< size_t > level_to_n_dofs
Map multigrid level to number of degrees of freedom for that level.
Definition multigrid.hpp:83
const size_t get_n_dofs(size_t level) const
Definition multigrid.hpp:352
std::vector< Eigen::Matrix< EleType, -1, 1 > > level_to_soln
Map multigrid level to solution (u) vector.
Definition multigrid.hpp:101
void display_error_off()
Definition multigrid.hpp:361
std::vector< Eigen::SparseMatrix< EleType > > level_to_coefficient_matrix
Map multigrid level to coefficient matrix A.
Definition multigrid.hpp:89
Multigrid(AMG::InterpolatorBase< EleType > *interpolator_, AMG::SmootherBase< EleType > *smoother_, const Eigen::SparseMatrix< EleType > &A, const Eigen::Matrix< EleType, -1, 1 > &b, size_t n_levels_, EleType tolerance_=1e-9, size_t compute_error_every_n_iters_=10, size_t n_iters_=100)
Construct a new Multigrid object.
Definition multigrid.hpp:151
Base class for smoothers that must implement a smooth function for the iterative solution of a linear...
Definition smoother.hpp:19
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