Fast Methods for Cosmological Simulations
FastSim serves as a tool for quick N-body simulations in modified gravity.
multigrid.cpp
Go to the documentation of this file.
1 #include "multigrid.h"
2 #include <iostream>
3 
4 // Simple int-int a^b power-function
5 inline size_t power(size_t a, size_t b){
6  size_t res = 1;
7  for(size_t i = 0; i < b; i++) {
8  res *= a;
9  }
10 #ifdef _BOUNDSCHECK
11  assert( (pow(1.0*a,1.0*b) - double(res)) < 0.5);
12 #endif
13  return res;
14 }
15 
16 template<size_t NDIM, typename T>
18 #ifdef _BOUNDSCHECK
19  assert(level < _Nlevel);
20 #endif
21  return _y[level];
22 }
23 
24 template<size_t NDIM, typename T>
25 const Grid<NDIM,T>& MultiGrid<NDIM,T>::get_grid(size_t level) const{
26 #ifdef _BOUNDSCHECK
27  assert(level < _Nlevel);
28 #endif
29  return _y[level];
30 }
31 
32 template<size_t NDIM, typename T>
34 #ifdef _BOUNDSCHECK
35  assert(level < _Nlevel);
36 #endif
37  return _y[level].get_y();
38 }
39 
40 template<size_t NDIM, typename T>
41 const T* MultiGrid<NDIM,T>::operator[](size_t level) const{
42 #ifdef _BOUNDSCHECK
43  assert(level < _Nlevel);
44 #endif
45  return _y[level].get_y();
46 }
47 
48 template<size_t NDIM, typename T>
49 T* MultiGrid<NDIM,T>::get_y(size_t level){
50 #ifdef _BOUNDSCHECK
51  assert(level < _Nlevel);
52 #endif
53  return _y[level].get_y();
54 }
55 
56 template<size_t NDIM, typename T>
57 T const * const MultiGrid<NDIM,T>::get_y(size_t level) const{
58 #ifdef _BOUNDSCHECK
59  assert(level < _Nlevel);
60 #endif
61  return _y[level].get_y();
62 }
63 
64 template<size_t NDIM, typename T>
65 T MultiGrid<NDIM,T>::get_y(size_t level, size_t i){
66 #ifdef _BOUNDSCHECK
67  assert(level < _Nlevel);
68 #endif
69  return _y[level].get_y(i);
70 }
71 
72 template<size_t NDIM, typename T>
73 T MultiGrid<NDIM,T>::get_y(size_t level, std::vector<size_t>& coord_list){
74  size_t ind = gridindex_from_coord(level, coord_list);
75 #ifdef _BOUNDSCHECK
76  assert(level < _Nlevel);
77 #endif
78  return _y[level].get_y(ind);
79 }
80 
81 template<size_t NDIM, typename T>
82 void MultiGrid<NDIM,T>::set_y(size_t level, size_t i, T value){
83 #ifdef _BOUNDSCHECK
84  assert(level < _Nlevel);
85 #endif
86  _y[level].set_y(i, value);
87 }
88 
89 template<size_t NDIM, typename T>
90 size_t MultiGrid<NDIM,T>::get_N(size_t level) const{
91 #ifdef _BOUNDSCHECK
92  assert(level < _Nlevel);
93 #endif
94  return _NinLevel[level];
95 }
96 
97 template<size_t NDIM, typename T>
98 size_t MultiGrid<NDIM,T>::get_Ntot(size_t level) const{
99 #ifdef _BOUNDSCHECK
100  assert(level < _Nlevel);
101 #endif
102  return _NtotinLevel[level];
103 }
104 
105 template<size_t NDIM, typename T>
107  return NDIM;
108 }
109 
110 template<size_t NDIM, typename T>
112  return _Nlevel;
113 }
114 
115 template<size_t NDIM, typename T>
117  return _NinLevel[_Nlevel-1];
118 }
119 
120 template<size_t NDIM, typename T>
121 MultiGrid<NDIM,T>::MultiGrid(Grid<NDIM, T> &y) : MultiGrid(y.get_N(), int(log2(y.get_N())+1)){
122  assert( power(2, _Nlevel - 1 ) == y.get_N() );
123  _y[0] = y;
124 }
125 
126 template<size_t NDIM, typename T>
127 MultiGrid<NDIM,T>::MultiGrid(Grid<NDIM, T> &y, size_t Nlevel) : MultiGrid(y.get_N(), Nlevel) {
128  _y[0] = y;
129 }
130 
131 template<size_t NDIM, typename T>
132 MultiGrid<NDIM,T>::MultiGrid(size_t N, size_t Nlevel) : _N(N), _Ntot(power(_N, NDIM)), _Nlevel(Nlevel), _NinLevel(std::vector<size_t>(_Nlevel, _N)), _NtotinLevel(std::vector<size_t>(_Nlevel, _Ntot)) {
133 
134  // Check that N is positive and divisible by 2^{Nlevel - 1}
135  assert( ( _N / power(2, _Nlevel - 1) ) * power(2, _Nlevel - 1) == _N && _N > 0);
136 
137  // We need atleast 1 level
138  assert( _Nlevel > 0 );
139 
140  // Total number of cells in finest level should not be too large (otherwise we cannot use [int])
141  assert( log2(INT_MAX) / log2(_N) > NDIM );
142 
143  // Allocate memory
144  _y = std::vector<Grid<NDIM, T> >(_Nlevel);
145  _y[0] = Grid<NDIM, T> (_N, 0.0);
146  for(size_t level = 1; level < _Nlevel; level++){
147  _NinLevel[level] = _NinLevel[level-1] / 2;
148  _NtotinLevel[level] = power(_NinLevel[level], NDIM);
149  assert(_NinLevel[level] > 0);
150  _y[level] = Grid<NDIM, T>(_NinLevel[level], 0.0);
151  }
152 }
153 
154 template<size_t NDIM, typename T>
155 void MultiGrid<NDIM,T>::restrict_down(size_t from_level, Grid<NDIM,T> &to_grid){
156 
157  // Cannot restict down if we are at the bottom
158  if(from_level + 1 >= _Nlevel) return;
159 
160  // Sanity check
161  assert( to_grid.get_N() == _y[from_level + 1].get_N() );
162 
163  // One over number of cells averaged over [ = 1 / 2^Ndim ]
164  T oneovernumcells = 1.0/T(1 << NDIM);
165 
166  // Pointers to Top and Bottom grid
167  T *Top = _y[from_level].get_y();
168  T *Bottom = to_grid.get_y();//_y[from_level+1].get_y();
169 
170  // Nodes on top and bottom level
171  size_t NTop = _NinLevel[from_level];
172  size_t NtotTop = _NtotinLevel[from_level];
173  size_t NBottom = _NinLevel[from_level+1];
174  size_t NtotBottom = _NtotinLevel[from_level+1];
175 
176  // Clear bottom array
177  std::fill_n(Bottom, NtotBottom, 0.0);
178 
179  // Compute N^j
180  std::vector<size_t> NpowTop(NDIM, 1);
181  std::vector<size_t> NpowBottom(NDIM, 1);
182  for(size_t j = 1; j < NDIM; j++){
183  NpowTop[j] = NpowTop[j-1] * NTop;
184  NpowBottom[j] = NpowBottom[j-1] * NBottom;
185  }
186 
187  // Loop over top grid
188  for (size_t i = 0; i < NtotTop; i++) {
189 
190  // Compute bottom array index the top cell 'belongs to'
191  size_t i_bottom = 0;
192  for(size_t j = 0; j < NDIM; j++){
193  size_t ii = i / NpowTop[j] % NTop;
194  i_bottom += (ii/2) * NpowBottom[j];
195  }
196 
197  // Add up to restricted grid
198  Bottom[i_bottom] += Top[i] * oneovernumcells;
199  }
200 
201 }
202 
203 template<size_t NDIM, typename T>
204 void MultiGrid<NDIM,T>::restrict_down(size_t from_level){
205  restrict_down(from_level, _y[from_level+1]);
206 }
207 
208 template<size_t NDIM, typename T>
210  for(size_t i = 0; i < _Nlevel-1; i++)
211  restrict_down(i);
212 }
213 
214 template<size_t NDIM, typename T>
215 std::vector<size_t> MultiGrid<NDIM,T>::coord_from_gridindex(size_t level, size_t i){
216 #ifdef _BOUNDSCHECK
217  assert(i < _NtotinLevel[level]);
218 #endif
219  std::vector<size_t> index(NDIM, 0);
220  size_t N = _NinLevel[level];
221  for(size_t idim = 0, n = 1; idim < NDIM; idim++, n *= N){
222  index[idim] = i / n % N;
223  }
224  return index;
225 }
226 
227 template<size_t NDIM, typename T>
228 size_t MultiGrid<NDIM,T>::gridindex_from_coord(size_t level, std::vector<size_t>& coord_list){
229  size_t index = 0;
230  for(size_t j = 0, N = 1; j < NDIM; j++, N *= _NinLevel[level])
231  index += coord_list[j] * N;
232  return index;
233 }
234 
235 template<size_t NDIM, typename T>
237  _N = _Ntot = _Nlevel = 0;
238  _NinLevel.clear();
239  _NtotinLevel.clear();
240  _y.clear();
241 }
242 
243 // Explicit template specialisation
244 template class MultiGrid<3,long double>;
245 
246 template class MultiGrid<3,double>;
247 template class MultiGrid<2,double>;
248 template class MultiGrid<1,double>;
249 template class MultiGrid<3,float>;
250 template class MultiGrid<2,float>;
251 template class MultiGrid<1,float>;
252 template class MultiGrid<1,std::complex<double> >;
size_t get_Ndim() const
Definition: multigrid.cpp:106
std::vector< size_t > _NinLevel
Definition: multigrid.h:27
size_t get_Nmin() const
Definition: multigrid.cpp:116
void restrict_down(size_t from_level)
Definition: multigrid.cpp:204
std::vector< size_t > coord_from_gridindex(size_t level, size_t i)
Definition: multigrid.cpp:215
size_t _N
Definition: multigrid.h:24
void restrict_down_all()
Definition: multigrid.cpp:209
size_t get_Ntot(size_t level=0) const
Definition: multigrid.cpp:98
size_t power(size_t a, size_t b)
Definition: multigrid.cpp:5
Definition: json.hpp:20160
Definition: grid.h:21
std::vector< size_t > _NtotinLevel
Definition: multigrid.h:28
size_t get_N(size_t level=0) const
Definition: multigrid.cpp:90
size_t get_Nlevel() const
Definition: multigrid.cpp:111
std::vector< Grid< NDIM, T > > _y
Definition: multigrid.h:29
void set_y(size_t level, size_t i, T value)
Definition: multigrid.cpp:82
size_t get_N() const
Definition: grid.cpp:135
T * get_y()
Definition: grid.cpp:41
size_t _Nlevel
Definition: multigrid.h:26
MultiGrid()
Definition: multigrid.h:34
size_t _Ntot
Definition: multigrid.h:25
size_t gridindex_from_coord(size_t level, std::vector< size_t > &coord_list)
Definition: multigrid.cpp:228
void clear()
Definition: multigrid.cpp:236
T * get_y(size_t level=0)
Definition: multigrid.cpp:49
float pow(float base, unsigned long int exp)
Definition: precision.hpp:39
T * operator[](size_t level)
Definition: multigrid.cpp:33
Grid< NDIM, T > & get_grid(size_t level=0)
Definition: multigrid.cpp:17
auto value(T const &val) -> Generator< T >
Definition: catch.hpp:3177