Fast Methods for Cosmological Simulations
FastSim serves as a tool for quick N-body simulations in modified gravity.
multigrid_solver.h
Go to the documentation of this file.
1 #ifndef _MULTIGRIDSOLVER_HEADER
2 #define _MULTIGRIDSOLVER_HEADER
3 #include <bitset>
4 #include <assert.h>
5 #include <iosfwd>
6 #include <vector>
7 #include <climits>
8 #include <iomanip>
9 #include <complex>
10 #include "grid.h"
11 #include "multigrid.h"
12 
13  //=============================================
14  // //
15  // A general multigrid solver to solve //
16  // PDEs in a domain with periodic BC //
17  // in any dimension. //
18  // //
19  // Implement: l_operator, dl_operator //
20  // and (optional) check_convergence //
21  // //
22  // The standard equation that is implemented //
23  // is Poissons eq.: D^2phi = rho, see //
24  // poisson_solver.h for this and how one can //
25  // use this class to solve general equations //
26  // //
27  // Any external fields needed to define the //
28  // PDE can be added to a grid-list //
29  // _ext_fields by running add_external_field //
30  // //
31  // _MAXSTEPS defines how many V-cycles we //
32  // do before giving up if convergence is not //
33  // reached. Change by running [set_maxsteps] //
34  // //
35  // _EPS_CONVERGE is a parameters defining //
36  // convergence. In standard implementation //
37  // we define convergence as _rms_res < eps //
38  // Change by running [set_epsilon] //
39  // //
40  // _NGRIDCOLOURS defines in which order we //
41  // sweep through the grid: sum of int-coord //
42  // mod _NGRIDCOLOURS. For 2 we have standard //
43  // chess-board ordering //
44  // //
45  //===========================================//
46 
47 template<size_t NDIM, typename T>
49 private:
50 
51  size_t _N; // The number of cells per dim in the main grid
52  size_t _Ntot; // Total number of cells in the main grid
53  size_t _Nmin; // The number of cells per dim in the smallest grid
54  size_t _Nlevel; // Number of levels
55 
56  // All the grids needed
57  MultiGrid<NDIM, T> _f; // The solution
58  MultiGrid<NDIM, T> _res; // The residual
59  MultiGrid<NDIM, T> _source; // The multigrid source (restriction of residual)
60 
61  // If the source of the equation depends on fields external to the solver they can
62  // be added by running add_ext_field and then used in l_operator etc.
63  std::vector<MultiGrid<NDIM,T> * > _ext_field;
64 
65  // Solver parameters
66  size_t _ngs_coarse = 2; // Number of NGS sweeps on coarse grid
67  size_t _ngs_fine = 2; // Number of NGS sweeps on the main grid
68  size_t _ngridcolours = 2; // The order we go through the grid:
69  // [Sum_i coord[i] % ngridcolour == j for j = 0,1,..,ngridcolour-1]
70 
71  // Book-keeping variables
72  size_t _tot_sweeps_domain_grid = 0; // Total number of sweeps on the domaingrid (level = 0)
73 
74  // Internal methods:
75  double calculate_residual(size_t level, Grid<NDIM,T>& res);
76  void prolonge_up_array(size_t to_level, Grid<NDIM,T>& BottomGrid, Grid<NDIM,T>& TopGrid);
78  void GaussSeidelSweep(size_t level, size_t curcolor, T *f);
79  void solve_current_level(size_t level);
80  void recursive_go_up(size_t to_level);
81  void recursive_go_down(size_t from_level);
82  void make_new_source(size_t level);
83 
84 protected:
85 
86  // Turn on verbose while solving
87  bool _verbose;
88 
89  // Internal methods:
90  void get_neighbor_gridindex(std::vector<size_t>& index_list, size_t i, size_t ngrid);
91 
92  // Convergence criterion (if the convergence check is not overwritten)
93  bool _conv_criterion_residual = true; // [True]: residual < eps [False]: residual/residual_i < eps
94  double _eps_converge = 1e-5; // Convergence criterion
95  size_t _maxsteps = 1000; // Maximum number of V-cycles
96  size_t _istep_vcycle = 0; // The number of V-cycles we are currenlty at
97 
98  // Residual information
99  double _rms_res; // Residual
100  double _rms_res_i; // The initial residual
101  double _rms_res_old; // The residual at the old step
102 
103 public:
104  // exit status of solver
106 
107  bool _store_all_residual = false; // Store the residual after every sweep
108  std::vector<double> _res_domain_array; // Array with the residuals after each step
109 
110  // Constructors
112  MultiGridSolver(size_t N) : MultiGridSolver(N, true) {}
113  MultiGridSolver(size_t N, bool verbose) : MultiGridSolver(N, 2, verbose) {}
114  MultiGridSolver(size_t N, size_t Nmin, bool verbose);
115 
116  size_t get_istep() const { return _istep_vcycle; };
117 
118  // Get a pointer to the solution array / grid
119  T *get_y(size_t level = 0);
120  T const * get_y(size_t level = 0) const;
121 
122  Grid<NDIM, T> &get_grid(size_t level = 0){ return _f.get_grid(level); };
123  const Grid<NDIM, T> &get_grid(size_t level = 0) const { return _f.get_grid(level); };
124 
125  MultiGrid<NDIM, T> &get_mlt_grid(size_t level = 0){ return _f; };
126  const MultiGrid<NDIM, T> &get_mlt_grid(size_t level = 0) const { return _f; };
127 
128  // Fetch values in externally added fields
129  T* get_external_field(size_t level, size_t field) { return _ext_field[field]->get_y(level); };
130  T const * get_external_field(size_t level, size_t field) const { return _ext_field[field]->get_y(level); };
131 
132  Grid<NDIM, T> &get_external_grid(size_t level, size_t field) { return _ext_field[field]->get_grid(level); };
133  const Grid<NDIM, T> &get_external_grid(size_t level, size_t field) const { return _ext_field[field]->get_grid(level); };
134 
135  size_t get_external_field_size() const { return _ext_field.size(); };
136 
137  // Get values of the multigrid-source used to store the restricted residual during the solve step
138  T get_multigrid_source(size_t level, size_t i) const { return _source[level][i]; };
139 
140  // Set precision parameters
141  void set_epsilon(double eps_converge);
142  void set_maxsteps(size_t maxsteps);
143  void set_ngs_sweeps(size_t ngs_fine, size_t ngs_coarse);
144  void set_convergence_criterion_residual(bool use_residual);
145  void set_Nlevel(size_t N);
146 
147  // Fetch info about the grids
148  size_t get_N(size_t level = 0) const;
149  size_t get_Ntot(size_t level = 0) const;
150  size_t get_Nlevel() const;
151 
152  // Add a pointer to an external grid if this grid is needed to define the PDE
154 
155  // Set the initial guess (uniform or from a grid)
156  void set_initial_guess(T guess);
157  void set_initial_guess(T *guess);
158  void set_initial_guess(Grid<NDIM,T>& guess);
159 
160  // Solve the PDE
161  Exit_Status solve();
162 
163  // Free up all memory
164  void clear();
165 
166  // Methods that may be implemented by user
167  virtual T upd_operator(const T f, const size_t level, const std::vector<size_t>& index_list, const T h) const;
168  virtual T l_operator(const size_t level, const std::vector<size_t>& index_list, bool addsource, const T h) const;
169  virtual T dl_operator(const size_t level, const std::vector<size_t>& index_list, const T h) const;
170  virtual void correct_sol(Grid<NDIM,T>& f, const Grid<NDIM,T>& corr, const size_t level);
171  virtual Exit_Status check_convergence();
172  virtual void check_solution(size_t level, Grid<NDIM,T>& sol);
173  void check_solution(size_t level); //< automatically retrieves reference to solution
174 };
175 
176 #endif
MultiGrid< NDIM, T > _source
Grid< NDIM, T > & get_grid(size_t level=0)
size_t _tot_sweeps_domain_grid
MultiGrid< NDIM, T > _f
MultiGrid< NDIM, T > & get_mlt_grid(size_t level=0)
void set_ngs_sweeps(size_t ngs_fine, size_t ngs_coarse)
T * get_y(size_t level=0)
void recursive_go_down(size_t from_level)
MultiGridSolver(size_t N)
void make_prolongation_array(Grid< NDIM, T > &f, Grid< NDIM, T > &Rf, Grid< NDIM, T > &df)
T * get_external_field(size_t level, size_t field)
void set_convergence_criterion_residual(bool use_residual)
size_t get_Nlevel() const
void set_epsilon(double eps_converge)
Exit_Status solve()
size_t get_N(size_t level=0) const
double calculate_residual(size_t level, Grid< NDIM, T > &res)
size_t get_Ntot(size_t level=0) const
Definition: grid.h:21
T const * get_external_field(size_t level, size_t field) const
Grid< NDIM, T > & get_external_grid(size_t level, size_t field)
std::vector< MultiGrid< NDIM, T > * > _ext_field
void solve_current_level(size_t level)
virtual T upd_operator(const T f, const size_t level, const std::vector< size_t > &index_list, const T h) const
const Grid< NDIM, T > & get_external_grid(size_t level, size_t field) const
size_t get_external_field_size() const
virtual T l_operator(const size_t level, const std::vector< size_t > &index_list, bool addsource, const T h) const
const MultiGrid< NDIM, T > & get_mlt_grid(size_t level=0) const
void recursive_go_up(size_t to_level)
void set_maxsteps(size_t maxsteps)
void make_new_source(size_t level)
void prolonge_up_array(size_t to_level, Grid< NDIM, T > &BottomGrid, Grid< NDIM, T > &TopGrid)
void set_initial_guess(T guess)
const Grid< NDIM, T > & get_grid(size_t level=0) const
size_t get_istep() const
void set_Nlevel(size_t N)
MultiGrid< NDIM, T > _res
T get_multigrid_source(size_t level, size_t i) const
void GaussSeidelSweep(size_t level, size_t curcolor, T *f)
virtual Exit_Status check_convergence()
MultiGridSolver(size_t N, bool verbose)
virtual void check_solution(size_t level, Grid< NDIM, T > &sol)
Grid< NDIM, T > & get_grid(size_t level=0)
Definition: multigrid.cpp:17
void add_external_grid(MultiGrid< NDIM, T > *field)
std::vector< double > _res_domain_array
void get_neighbor_gridindex(std::vector< size_t > &index_list, size_t i, size_t ngrid)
virtual T dl_operator(const size_t level, const std::vector< size_t > &index_list, const T h) const
virtual void correct_sol(Grid< NDIM, T > &f, const Grid< NDIM, T > &corr, const size_t level)