Fast Methods for Cosmological Simulations
FastSim serves as a tool for quick N-body simulations in modified gravity.
continuity.cpp
Go to the documentation of this file.
1 #include "continuity_solver.h"
2 #include <fstream>
3 #include <fftw3.h>
4 
5 //====================================
6 //
7 // This is an example of how to use the
8 // multigrid solver class for solving
9 // the continuity equation (assuming
10 // ddelta/dt = f delta)
11 //
12 // fdelta + D[(1+delta) v] = 0
13 //
14 //====================================
15 
16 //====================================
17 // The dim of the equation
18 //====================================
19 #define _NDIM 3
20 
21 //====================================
22 // The type (double,float,complex,...)
23 //====================================
24 typedef double DType;
25 
26 //====================================
27 // Parameters for the PDE
28 //====================================
31 DType growthfachubble = pow(0.26, 0.55);
32 
33 //====================================
34 // Methods below
35 //====================================
37 void assign_to_grid(MultiGrid<_NDIM, DType>& f, std::string filename, std::string store_grid_file);
38 void compute_v(Grid<_NDIM, DType> phi, DType boxsize);
39 bool exists(std::string filename);
40 
41 //==============================================================================
42 // Read particle-file and assign the particles to grid to compute rho(x,y,z,...)
43 //==============================================================================
44 void assign_to_grid(MultiGrid<_NDIM, DType>& f, std::string filename, std::string store_grid_filename){
45 
46  unsigned int npart = 0;
47  unsigned int N = f.get_N();
48  unsigned int Ntot = f.get_Ntot();
49  DType *y = f.get_y(0);
50 
51  std::cout << "Grid N: " << N << " Ntot: " << Ntot << std::endl;
52 
53  // Open particle file
54  std::ifstream fp;
55  fp.open( filename.c_str() );
56 
57  fp >> npart;
58  std::cout << "Npart: " << npart << std::endl;
59 
60  // Velocity grid
61  Grid<_NDIM,DType> vel(f.get_grid(0));
62 
63  // Assigne particles to grid
64  double vrms = 0.0;
65  for(unsigned int i = 0; i < npart; i++){
66  double xx, yy, zz;
67  double vx, vy, vz, v2;
68 
69  fp >> xx;
70  fp >> yy;
71  fp >> zz;
72  fp >> vx;
73  fp >> vy;
74  fp >> vz;
75 
76  v2 = vx*vx + vy*vy + vz*vz;
77  vrms += v2;
78 
79  unsigned int ix = int(xx * N);
80  unsigned int iy = int(yy * N);
81  unsigned int iz = int(zz * N);
82  if(ix == N) ix = 0;
83  if(iy == N) iy = 0;
84  if(iz == N) iz = 0;
85 
86  int index = ix + N*(iy + N*iz);
87 
88  vel[index] += sqrt(v2);
89  y[index] += 1.0;
90  }
91  vrms = sqrt(vrms / double(npart));
92  std::cout << "Particles read vrms = " << vrms << std::endl;
93 
94  // Normalize to delta = rho/rho_mean - 1
95  double rhomean = double(npart) / double(Ntot);
96  double sum = 0.0, max = -1e30, min = 1e30;
97  for(unsigned int i = 0; i < Ntot; i++){
98  y[i] = y[i] / rhomean - 1.0;
99  if(y[i] > max) max = y[i];
100  if(y[i] < min) min = y[i];
101  sum += y[i];
102  }
103  std::cout << "Average: " << sum / double(Ntot) << " Max: " << max << " Min: " << min << std::endl;
104 
105  // Save grid to file...
106  f.get_grid().dump_to_file(store_grid_filename);
107 }
108 
109 //===============================================================================
110 // Compute the velocity from the solution to the PDE (sloopy way; use FFT instead)
111 //===============================================================================
112 void compute_v(Grid<_NDIM, DType> phi, DType boxsize){
113 
114  unsigned int Ntot = phi.get_Ntot();
115  unsigned int N = phi.get_N();
116 
117  // This is (1/gridsize * H0 * B0) = (N * 100 * Boxsize_in_Mpc/h) km/s
118  DType norm = DType(N) * 100.0 * boxsize;
119 
120  double vrms = 0.0;
121  for(unsigned int i = 0; i < Ntot; i++){
122  std::vector<unsigned int> coord = phi.index_list(i);
123  std::vector<unsigned int> iplus(_NDIM, 0);
124 
125  for(unsigned int j = 0; j < _NDIM; j++)
126  iplus[j] = coord[j] + 1 < N ? coord[j] + 1 : 0;
127 
128  // Specialize to NDIM = 3
129  unsigned int ixp = phi.grid_index_3d(iplus[0], coord[1], coord[2]);
130  unsigned int iyp = phi.grid_index_3d(coord[0], iplus[1], coord[2]);
131  unsigned int izp = phi.grid_index_3d(coord[0], coord[1], iplus[2]);
132 
133  double v_x2 = std::norm((phi[ixp] - phi[i])*norm);
134  double v_y2 = std::norm((phi[iyp] - phi[i])*norm);
135  double v_z2 = std::norm((phi[izp] - phi[i])*norm);
136  double v2 = v_x2 + v_y2 + v_z2;
137  vrms += v2;
138  }
139  std::cout << "Vrms: " << std::sqrt(vrms/double(Ntot)) << " km/s" << std::endl;
140 }
141 
142 //=====================================
143 // Solve linearized equation using FFT
144 //=====================================
146  int n = drho.get_N(), nover2 = n/2, n2 = n*n, ntot = drho.get_Ntot();
147  double fac = -1.0/(4.0*acos(-1)*acos(-1)) * 1.0/double(n * n * n);
148  fftw_complex *out = (fftw_complex *) fftw_malloc(sizeof(fftw_complex) * n*n*n);
149  fftw_plan fwd = fftw_plan_dft_3d(n, n, n, out, out, FFTW_FORWARD, FFTW_ESTIMATE);
150  fftw_plan bwd = fftw_plan_dft_3d(n, n, n, out, out, FFTW_BACKWARD, FFTW_ESTIMATE);
151 
152  // Set source
153  double rhomean = 0.0;
154  for(int i = 0; i < ntot; i++){
155  out[i][0] = -growthfachubble * drho[i];
156  out[i][1] = 0.0;
157  rhomean += out[i][0];
158  }
159  std::cout << "Rhomean: " << rhomean / double(ntot) << std::endl;
160 
161  fftw_execute(fwd);
162 
163  // Divide by laplacian
164  for(int i=0;i<n;i++){
165  int ii = (i < nover2 ? i: i-n);
166  for(int j=0;j<n;j++){
167  int jj = (j < nover2 ? j: j-n);
168  for(int k=0;k<n;k++){
169  int kk = (k < nover2 ? k: k-n);
170  int ind = i + j*n + k*n2;
171  if(ind > 0){
172  double facnow = fac/(ii*ii+jj*jj+kk*kk);
173  out[ind][0] *= facnow;
174  out[ind][1] *= facnow;
175  }
176  }
177  }
178  }
179  out[0][0] = 0.0;
180  out[0][1] = 0.0;
181 
182  fftw_execute(bwd);
183 
184  // Copy over solution
185  for(int i = 0; i < ntot; i++){
186  sol[i] = out[i][0];
187  }
188 
189  fftw_free(out);
190 }
191 
192 //==================================
193 // Check if file exists
194 //==================================
195 bool exists(std::string filename){
196  std::ifstream fp(filename.c_str());
197  return fp.good();
198 }
199 
200 int main(){
201  int NgridPerDim = 64;
202  bool verbose = true;
203  DType boxsize = 200.0;
204  std::string prefix = "../test_data/rho_";
205  std::string grid_filename = prefix + std::to_string(NgridPerDim) + ".dat";
206  std::string part_filename = "../test_data/data.ascii";
208 
209  // Read grid from file
210  if(exists(grid_filename)){
211 
212  // Read grid from file
213  Grid<_NDIM, DType> tmp;
214  tmp.read_from_file(grid_filename);
215  NgridPerDim = tmp.get_N();
216 
217  // Make multigrid from grid read from file
218  rho = MultiGrid<_NDIM, DType>(tmp);
219 
220  // Restict down density to all levels
221  rho.restrict_down_all();
222 
223  } else {
224 
225  // Make a density-grid
226  rho = MultiGrid<_NDIM, DType>(NgridPerDim);
227 
228  // Read particles from file and assign to grid
229  assign_to_grid(rho, part_filename, grid_filename);
230 
231  // Restict down density to all levels
232  rho.restrict_down_all();
233  }
234 
235  // Solve with fft
236  Grid<3,double> fft_sol = rho.get_grid(0);
237  solve_with_fft(rho.get_grid(0), fft_sol);
238  compute_v(fft_sol, boxsize);
239 
240  // Set up solver
241  ContinuitySolver<_NDIM, DType> sol(NgridPerDim, verbose);
242 
243  // Set some options (rhomin = rhomax = 1 => linear eq. | f(a) H(a))/H0 = growthfachubble)
247 
248  sol.set_initial_guess(fft_sol);
249 
250  // Add pointer to the source grid to the solver
251  sol.add_external_grid(&rho);
252 
253  // Set some parameters
254  sol.set_ngs_sweeps(4, 10);
255  sol.set_epsilon(1e-4);
256 
257  // Solve the equation
258  sol.solve();
259 
260  Grid<3,double> &mgsol = sol.get_grid(0);
261  Grid<3,double> err = (mgsol - fft_sol)/sqrt(fft_sol*fft_sol + mgsol*mgsol);
262  std::cout << "Difference wrt linear solution: " << err.rms_norm() * 100.0 << " %" << std::endl;
263 
264  // Compute v
265  compute_v(sol.get_grid(), boxsize);
266 }
267 
Grid< NDIM, T > & get_grid(size_t level=0)
double double
Definition: precision.hpp:19
std::vector< size_t > index_list(size_t i)
Definition: grid.cpp:102
void set_ngs_sweeps(size_t ngs_fine, size_t ngs_coarse)
void restrict_down_all()
Definition: multigrid.cpp:209
#define _NDIM
Definition: continuity.cpp:19
size_t get_Ntot(size_t level=0) const
Definition: multigrid.cpp:98
void set_epsilon(double eps_converge)
Exit_Status solve()
void set_rhomax(double rhomax)
Definition: grid.h:21
void solve_with_fft(Grid< 3, double > &drho, Grid< 3, double > &sol)
Definition: continuity.cpp:145
size_t get_N(size_t level=0) const
Definition: multigrid.cpp:90
size_t grid_index_3d(size_t ix, size_t iy, size_t iz)
Definition: grid.cpp:124
int iz
Definition: mfunc_bm.py:17
size_t get_N() const
Definition: grid.cpp:135
std::ostream & cout()
DType rhomin_in_grad
Definition: continuity.cpp:29
size_t get_Ntot() const
Definition: grid.cpp:141
void set_growthfachubble(double growthfachubble)
double DType
Definition: continuity.cpp:24
Grid< NDIM, T > sqrt(Grid< NDIM, T > lhs)
Definition: grid.h:231
DType growthfachubble
Definition: continuity.cpp:31
static T max(const std::vector< T > &data)
Definition: core_app.cpp:61
void set_initial_guess(T guess)
T * get_y(size_t level=0)
Definition: multigrid.cpp:49
void compute_v(Grid< 3, DType > phi, DType boxsize)
Definition: continuity.cpp:112
T min(const std::vector< T > &data)
Definition: chameleon.cpp:140
void read_from_file(std::string filename)
Definition: grid.cpp:165
float pow(float base, unsigned long int exp)
Definition: precision.hpp:39
Grid< NDIM, T > & get_grid(size_t level=0)
Definition: multigrid.cpp:17
void add_external_grid(MultiGrid< NDIM, T > *field)
int main()
Definition: continuity.cpp:200
double rms_norm()
Definition: grid.h:238
bool exists(std::string filename)
Definition: continuity.cpp:195
void assign_to_grid(MultiGrid< 3, DType > &f, std::string filename, std::string store_grid_file)
Definition: continuity.cpp:44
DType rhomax_in_grad
Definition: continuity.cpp:30
void set_rhomin(double rhomin)
std::complex< double > DType
Definition: poisson.cpp:29