Fast Methods for Cosmological Simulations
FastSim serves as a tool for quick N-body simulations in modified gravity.
core_mesh.cpp
Go to the documentation of this file.
1 
9 #include "core_mesh.h"
10 
11 #ifndef ORDER
12 #define ORDER 1
13 #endif
14 
15 template <typename T> static int sgn(T val)
16 {
17  return (T(0) < val) - (val < T(0));
18 }
19 
20 void get_k_vec(size_t N, size_t index, int* k_vec)
21 {
22  k_vec[0] = index / ((N/2 + 1)*N);
23  k_vec[1] = (index / (N/2 + 1)) % N;
24  k_vec[2] = index % (N/2 + 1);
25 
26  for (unsigned int i = 0; i<2; i++) if (k_vec[i] > N/2) k_vec[i] -= N; // k_vec[2] is ALWAYS less or equal than N/2 (real FFTW)
27 }
28 
29 void get_k_vec(size_t N, size_t index, Vec_3D<int> &k_vec)
30 {
31  k_vec[0] = index / ((N/2 + 1)*N);
32  k_vec[1] = (index / (N/2 + 1)) % N;
33  k_vec[2] = index % (N/2 + 1);
34 
35  for (unsigned int i = 0; i<2; i++) if (k_vec[i] > N/2) k_vec[i] -= N; // k_vec[2] is ALWAYS less or equal than N/2 (real FFTW)
36 }
37 
38 FTYPE_t get_k_sq(size_t N, size_t index)
39 {
40  int k_vec[3];
41  FTYPE_t tmp = 0;
42  get_k_vec(N, index, k_vec);
43  for (unsigned int i = 0; i<3; i++) tmp += pow2(k_vec[i]);
44  return tmp;
45 }
46 
47 template<typename T>
48 static typename std::enable_if<std::is_integral<T>::value, T>::type get_per(T vec, size_t per)
49 {
50  static_assert(std::is_integral<T>::value, "Integral required.");
51  if ((vec >= (int)per) || (vec < 0) ){
52  vec %= (int)per;
53  return (vec < 0) ? vec + (int)per : vec;
54  }
55  else return vec;
56 }
57 
58 template<typename T>
59 static typename std::enable_if<!std::is_integral<T>::value, T>::type get_per(T vec, size_t per)
60 {
61  static_assert(!std::is_integral<T>::value, "Non-integral required.");
62  return ((vec >= per) || (vec < 0) ) ? vec - per * floor( vec / per ) : vec;
63 }
64 
65 template<typename T>
66 void get_per(Vec_3D<T> &position, size_t per)
67 {
68  for (T& pos : position) pos = get_per(pos, per);
69 }
70 
71 template<typename T>
72 void get_per(Vec_3D<T> &position, size_t perx, size_t pery, size_t perz)
73 {
74  position[0] = get_per(position[0], perx);
75  position[1] = get_per(position[1], pery);
76  position[2] = get_per(position[2], perz);
77 }
78 
79 void get_per(std::vector<Particle_v<FTYPE_t>>& particles, const size_t per)
80 {
81  const size_t Np = particles.size();
82  #pragma omp parallel for
83  for (size_t i = 0; i < Np; i++)
84  {
85  get_per(particles[i].position, per);
86  }
87 }
88 
89 template<typename T>
90 inline T get_distance_1D(const T x_1, const T x_2, const size_t per)
91 {
92  T d = std::abs(x_2 - x_1);
93  if (d <= per / 2) return d; // most probable, first condition
94  else if (d <= per) return per - d;
95  else d = fmod(d, T(per)); // fmod unlikely to evaluate, speed up code
96  if (d <= per / 2) return d;
97  else return per - d;
98 }
99 
100 template<typename T>
101 inline T get_distance_1D(const T x_1, const int x_2, const size_t per){ return get_distance_1D(x_1, (T)x_2, per); }
102 
103 template<typename T>
104 inline T get_sgn_distance_1D(T x_from, T x_to, size_t per)
105 { // return signed (oriented) distance, e.g. x_to - x_from (no periodicity)
106  // periodicity makes this a little bit trickier
107  T d = x_from - x_to;
108  if (std::abs(d) <= per / 2) return d; // most probable, first condition
109  else if (std::abs(d) <= per) return d-sgn(d)*per;
110  else d = fmod(d, T(per)); // fmod unlikely to evaluate, speed up code
111  if (std::abs(d) <= per / 2) return d;
112  else return d-sgn(d)*per;
113 }
114 
115 FTYPE_t get_distance(const Vec_3D<FTYPE_t> &x_1, const Vec_3D<FTYPE_t> &x_2, int per)
116 {
117  FTYPE_t dst = 0;
118  for (unsigned int i = 0; i < 3; i++) dst+= pow2(get_distance_1D(x_1[i], x_2[i], per));
119  return sqrt(dst);
120 }
121 
122 Vec_3D<FTYPE_t> get_sgn_distance(const Vec_3D<FTYPE_t> &x_from, const Vec_3D<FTYPE_t> &x_to, size_t per)
123 {
124  Vec_3D<FTYPE_t> dst;
125  for (unsigned int i = 0; i < 3; i++) dst[i] = get_sgn_distance_1D(x_from[i], x_to[i], per);
126  return dst;
127 }
128 
129 template<size_t N> static FTYPE_t wgh_sch(const Vec_3D<FTYPE_t> &x, const Vec_3D<int>& y, size_t mesh_num);
130 // The weighting scheme used to assign values to the mesh points or vice versa
131 // Return value of assigment function on mesh point y from particle in x
132 
133 // template<> FTYPE_t wgh_sch<0>(const Vec_3D<FTYPE_t> &x, Vec_3D<int> y, size_t mesh_num)
134 // { // NGP: Nearest grid point
135 // get_per(y, mesh_num);
136 // for (unsigned int i = 0; i < 3; i++) if ((int)x[i] != y[i]) return 0;
137 // return 1;
138 // }
139 
140 template<> FTYPE_t wgh_sch<1>(const Vec_3D<FTYPE_t> &x, const Vec_3D<int>& y, size_t mesh_num)
141 { // CIC: Cloud in cells
142  FTYPE_t dx, w = 1;
143  for (unsigned int i = 0; i < 3; i++)
144  {
145  dx = get_distance_1D(x[i], y[i], mesh_num);
146  if (dx > 1) return 0;
147  else w *= 1 - dx;
148  }
149  return w;
150 }
151 
152 template<> FTYPE_t wgh_sch<2>(const Vec_3D<FTYPE_t> &x, const Vec_3D<int>& y, size_t mesh_num)
153 { // TSC: Triangular shaped clouds
154  FTYPE_t dx, w = 1;
155  for (unsigned int i = 0; i < 3; i++)
156  {
157  dx = get_distance_1D(x[i], y[i], mesh_num);
158  if (dx > 1.5) return 0;
159  else if (dx > 0.5) w *= pow2(1.5 - dx) / 2;
160  else w *= 3 / FTYPE_t(4) - dx*dx;
161  }
162  return w;
163 }
164 
170 template<unsigned int points>
171 IT<points>::IT(const Vec_3D<FTYPE_t> &pos): counter(0)
172 {
173  for(size_t i = 0; i < 3; i++){
174  vec[i] = (int)(pos[i] - 0.5*(int(points) - 2));
175  }
176 }
177 
178 template<unsigned int points>
179 IT<points>::IT(const Vec_3D<FTYPE_t> &pos, FTYPE_t Hc): counter(0)
180 {
181  for(size_t i = 0; i < 3; i++){
182  vec[i] = (int)(pos[i]/Hc) - 1;
183  }
184 }
185 
186 template<unsigned int points>
188  if (++counter == (points*points*points)) return false;
189  vec[2]++;
190  if ((counter % points) == 0){
191  vec[2] -= points;
192  vec[1]++;
193  if ((counter % (points*points)) == 0){
194  vec[1] -= points;
195  vec[0]++;
196  }
197  }
198  return true;
199 }
200 
201 void assign_to(Mesh& field, const Vec_3D<FTYPE_t> &position, const FTYPE_t value)
202 {
203  IT<ORDER+1> it(position);
204  do{
205  #pragma omp atomic
206  field(it.vec) += value * wgh_sch<ORDER>(position, it.vec, field.N);
207  } while( it.iter() );
208 }
209 
210 void assign_to(std::vector<Mesh>& field, const Vec_3D<FTYPE_t> &position, const Vec_3D<FTYPE_t>& value)
211 {
212  IT<ORDER+1> it(position);
213  FTYPE_t w;
214  do{
215  w = wgh_sch<ORDER>(position, it.vec, field[0].N);
216  for (size_t i = 0; i < 3; i++)
217  {
218  #pragma omp atomic
219  field[i](it.vec) += value[i] * w;
220  }
221  } while( it.iter() );
222 }
223 
224 void assign_from(const Mesh &field, const Vec_3D<FTYPE_t> &position, FTYPE_t& value, FTYPE_t mod)
225 {
226  IT<ORDER+1> it(position);
227  do{
228  #pragma omp atomic
229  value += field(it.vec) * mod * wgh_sch<ORDER>(position, it.vec, field.N);
230  } while( it.iter() );
231 }
232 
233 void assign_from(const std::vector<Mesh> &field, const Vec_3D<FTYPE_t> &position, Vec_3D<FTYPE_t>& value, FTYPE_t mod)
234 {
235  IT<ORDER+1> it(position);
236  FTYPE_t w;
237  do{
238  w = mod * wgh_sch<ORDER>(position, it.vec, field[0].N);
239  for (unsigned int i = 0; i < 3; i++)
240  {
241  #pragma omp atomic
242  value[i] += field[i](it.vec) * w;
243  }
244  } while( it.iter() );
245 }
246 
248 {
249  FFTW_EXEC_R2C(p_F, rho.real(), rho.complex());
250  rho /= pow((FTYPE_t)rho.N, 3); //< normalization
251 }
252 
254 {
255  FFTW_EXEC_C2R(p_B, rho.complex(), rho.real());
256 }
257 
258 void fftw_execute_dft_r2c_triple(const FFTW_PLAN_TYPE &p_F, std::vector<Mesh>& rho)
259 {
260  for (unsigned int i = 0; i < 3; i++) fftw_execute_dft_r2c(p_F, rho[i]);
261 }
262 
263 void fftw_execute_dft_c2r_triple(const FFTW_PLAN_TYPE &p_B, std::vector<Mesh>& rho)
264 {
265  for (unsigned int i = 0; i < 3; i++) fftw_execute_dft_c2r(p_B, rho[i]);
266 }
267 
268 template void get_per(Vec_3D<int>&, size_t);
269 template void get_per(Vec_3D<int>&, size_t, size_t, size_t);
270 template void get_per(Vec_3D<size_t>&, size_t);
271 template void get_per(Vec_3D<size_t>&, size_t, size_t, size_t);
272 template void get_per(Vec_3D<FTYPE_t>&, size_t);
273 template void get_per(Vec_3D<FTYPE_t>&, size_t, size_t, size_t);
274 
275 template class IT<ORDER+1>;
276 template class IT<3>;
FFTW_COMPLEX_TYPE * complex()
get fftw_complex pointer to data
Definition: class_mesh.hpp:111
double get_k_sq(size_t N, size_t index)
Definition: core_mesh.cpp:38
class handling particles (position only)
T * real()
Definition: class_mesh.hpp:36
double wgh_sch< 1 >(const Vec_3D< double > &x, const Vec_3D< int > &y, size_t mesh_num)
Definition: core_mesh.cpp:140
Vec_3D< double > get_sgn_distance(const Vec_3D< double > &x_from, const Vec_3D< double > &x_to, size_t per)
Definition: core_mesh.cpp:122
static double wgh_sch(const Vec_3D< double > &x, const Vec_3D< int > &y, size_t mesh_num)
T get_distance_1D(const T x_1, const T x_2, const size_t per)
Definition: core_mesh.cpp:90
void fftw_execute_dft_r2c(const FFTW_PLAN_TYPE &p_F, Mesh &rho)
compute forward (real to complex) FFT on mesh (inplace)
Definition: core_mesh.cpp:247
bool iter()
Definition: core_mesh.cpp:187
: creates a mesh of N*N*(N+2) cells
Definition: class_mesh.hpp:95
void assign_to(Mesh &field, const Vec_3D< double > &position, const double value)
Definition: core_mesh.cpp:201
: class for effective iteration of cube of mesh cells
Definition: core_mesh.h:66
void fftw_execute_dft_c2r_triple(const FFTW_PLAN_TYPE &p_B, std::vector< Mesh > &rho)
compute three backward (complex to real) FFTs on vector of meshes (inplace)
Definition: core_mesh.cpp:263
T pow2(T base)
Definition: precision.hpp:52
void fftw_execute_dft_c2r(const FFTW_PLAN_TYPE &p_B, Mesh &rho)
compute backward (complex to real) FFT on mesh (inplace)
Definition: core_mesh.cpp:253
double get_distance(const Vec_3D< double > &x_1, const Vec_3D< double > &x_2, int per)
Definition: core_mesh.cpp:115
double wgh_sch< 2 >(const Vec_3D< double > &x, const Vec_3D< int > &y, size_t mesh_num)
Definition: core_mesh.cpp:152
Grid< NDIM, T > sqrt(Grid< NDIM, T > lhs)
Definition: grid.h:231
static CCL_BEGIN_DECLS double x[111][8]
size_t N
Definition: class_mesh.hpp:102
static std::enable_if< std::is_integral< T >::value, T >::type get_per(T vec, size_t per)
Definition: core_mesh.cpp:48
#define FFTW_PLAN_TYPE
Definition: precision.hpp:26
#define FFTW_EXEC_C2R
Definition: precision.hpp:35
size_t counter
Definition: core_mesh.h:72
T get_sgn_distance_1D(T x_from, T x_to, size_t per)
Definition: core_mesh.cpp:104
#define FFTW_EXEC_R2C
Definition: precision.hpp:34
void get_k_vec(size_t N, size_t index, int *k_vec)
Definition: core_mesh.cpp:20
basic functions to work with mesh
float pow(float base, unsigned long int exp)
Definition: precision.hpp:39
: class handling basic 3D-vector functions, definitions
auto value(T const &val) -> Generator< T >
Definition: catch.hpp:3177
void fftw_execute_dft_r2c_triple(const FFTW_PLAN_TYPE &p_F, std::vector< Mesh > &rho)
compute three forward (real to complex) FFTs on vector of meshes (inplace)
Definition: core_mesh.cpp:258
void assign_from(const Mesh &field, const Vec_3D< double > &position, double &value, double mod)
Definition: core_mesh.cpp:224
IT(const Vec_3D< double > &pos)
Definition: core_mesh.cpp:171
static double w[2][28][111]
Definition: ccl_emu17.c:33
Vec_3D< size_t > vec
Definition: core_mesh.h:73
static int sgn(T val)
Definition: core_mesh.cpp:15