CosmoGRaPH v0.0
Array.h
1 #ifndef COSMO_UTILS_ARRAY_H
2 #define COSMO_UTILS_ARRAY_H
3 
4 #include <string>
5 #include <utility>
6 #include <iostream>
7 
8 #include "TriCubicInterpolator.h"
9 
10 namespace cosmo
11 {
12 
13 template<typename IT, typename RT>
15 {
16  public:
17  IT nx, ny, nz;
18  IT pts = 0;
19 
20  std::string name;
21 
22  RT* _array;
23 
24  CosmoArray() {}
25 
26  CosmoArray(IT n_in)
27  {
28  init(n_in, n_in, n_in);
29  }
30 
31  CosmoArray(IT nx_in, IT ny_in, IT nz_in)
32  {
33  init(nx_in, ny_in, nz_in);
34  }
35 
36  ~CosmoArray()
37  {
38  if(pts > 0)
39  delete [] _array;
40  }
41 
42  void setName(std::string name_in)
43  {
44  name = name_in;
45  }
46 
47  void init(IT nx_in, IT ny_in, IT nz_in)
48  {
49  nx = nx_in;
50  ny = ny_in;
51  nz = nz_in;
52 
53  pts = nx*ny*nz;
54 
55  _array = new RT[pts];
56 
57 #pragma omp parallel for
58  for(IT i=0; i<pts; ++i)
59  {
60  _array[i] = 0.0;
61  }
62  }
63 
64  IT _IT_mod(IT n, IT d) const
65  {
66  IT mod = n % d;
67  if(mod < 0)
68  mod += d;
69  return mod;
70  }
71 
72  RT sum()
73  {
74  RT res = 0.0;
75 
76 #pragma omp parallel for reduction(+:res)
77  for(IT i=0; i<pts; ++i)
78  {
79  res += _array[i];
80  }
81 
82  return res;
83  }
84 
85  RT avg()
86  {
87  return sum() / (RT)pts;
88  }
89 
90  RT min()
91  {
92  RT min_res = 1e100;
93 #pragma omp parallel for
94  for(IT i = 0; i<pts; i++)
95  {
96 #pragma omp critical
97  if(_array[i] < min_res)
98  min_res = _array[i];
99  }
100  return min_res;
101  }
102 
103  RT max()
104  {
105  RT max_res = -1e100;
106 #pragma omp parallel for
107  for(IT i = 0; i<pts; i++)
108  {
109 #pragma omp critical
110  {
111  if(_array[i] > max_res)
112  max_res = _array[i];
113  }
114  }
115 
116  return max_res;
117  }
118 
119  RT abs_max()
120  {
121  RT max_res = 0;
122 #pragma omp parallel for
123  for(IT i = 0; i<pts; i++)
124  {
125 #pragma omp critical
126  {
127  if(fabs(_array[i]) > max_res)
128  max_res = fabs(_array[i]);
129  }
130  }
131 
132  return max_res;
133  }
134 
135 
136  RT L2_norm()
137  {
138  RT L2 = 0;
139 #pragma omp parallel for reduction(+:L2)
140  for(IT i=0; i<pts; ++i)
141  {
142  L2 += _array[i] * _array[i];
143  }
144 
145  return sqrt(L2);
146  }
147 
148 
149  IT idx(IT i_in, IT j_in, IT k_in)
150  {
151  IT i=i_in, j=j_in, k=k_in;
152 
153  // indexing only works down to negative 100*(nx, ny, nz)?
154  // Using this is slow. Use a macro instead.
155  if(i_in < 0 || i_in >= nx) i = (i_in%nx + nx)%nx;
156  if(j_in < 0 || j_in >= ny) j = (j_in%ny + ny)%ny;
157  if(k_in < 0 || k_in >= nz) k = (k_in%nz + nz)%nz;
158  return ( i*ny*nz + j*nz + k );
159  }
160 
161  RT& operator()(IT i, IT j, IT k)
162  {
163  IT x = idx(i, j, k);
164  return _array[x];
165  }
166 
167  CosmoArray& operator=(const CosmoArray& other) {
168  // check for self-assignment
169  if(&other == this)
170  return *this;
171 
172  this->nx = other.nx;
173  this->nz = other.ny;
174  this->ny = other.nz;
175  this->pts = other.pts;
176  this->name = other.name;
177 
178  #pragma omp parallel for
179  for(IT i=0; i<pts; ++i)
180  {
181  this->_array[i] = other._array[i];
182  }
183 
184  return *this;
185  }
186 
187  RT& operator[](IT idx)
188  {
189  return _array[idx];
190  }
191 
192  // Weighted averaging / trilinear interpolation via
193  // https://en.wikipedia.org/wiki/Trilinear_interpolation#Method
194  RT getInterpolatedValue(RT i_in, RT j_in, RT k_in)
195  {
196  IT il = i_in < 0 ? (IT) i_in - 1 : (IT) i_in; // Index "left" of i
197  RT id = i_in - il; // fractional difference
198  IT jl = j_in < 0 ? (IT) j_in - 1 : (IT) j_in; // same as ^ but j
199  RT jd = j_in - jl;
200  IT kl = k_in < 0 ? (IT) k_in - 1 : (IT) k_in; // same as ^ but k
201  RT kd = k_in - kl;
202 
203  RT c00 = _array[idx(il, jl, kl)]*(1-id) + _array[idx(il+1, jl, kl)]*id;
204  RT c01 = _array[idx(il, jl, kl+1)]*(1-id) + _array[idx(il+1, jl, kl+1)]*id;
205  RT c10 = _array[idx(il, jl+1, kl)]*(1-id) + _array[idx(il+1, jl+1, kl)]*id;
206  RT c11 = _array[idx(il, jl+1, kl+1)]*(1-id) + _array[idx(il+1, jl+1, kl+1)]*id;
207  RT c0 = c00*(1-jd) + c10*jd;
208  RT c1 = c01*(1-jd) + c11*jd;
209 
210  return c0*(1-kd) + c1*kd;
211  }
212 
213  // Catmull-Rom cubic spline
214  RT CINT(RT u, RT p0, RT p1, RT p2, RT p3)
215  {
216  return 0.5*(
217  (u*u*(2.0 - u) - u)*p0
218  + (u*u*(3.0*u - 5.0) + 2)*p1
219  + (u*u*(4.0 - 3.0*u) + u)*p2
220  + u*u*(u - 1.0)*p3
221  );
222  }
223 
224  RT getTriCubicInterpolatedValue(RT i_in, RT j_in, RT k_in)
225  {
226  IT il = i_in < 0 ? (IT) i_in - 1 : (IT) i_in; // Index "left" of i
227  RT id = i_in - il; // fractional difference
228  // special 1d case
229  if(ny==1 && nz==1)
230  {
231  return CINT(id,
232  _array[idx(il-1, 0, 0)], _array[idx(il, 0, 0)],
233  _array[idx(il+1, 0, 0)], _array[idx(il+2, 0, 0)]);
234  }
235 
236  IT jl = j_in < 0 ? (IT) j_in - 1 : (IT) j_in; // same as ^ but j
237  RT jd = j_in - jl;
238  IT kl = k_in < 0 ? (IT) k_in - 1 : (IT) k_in; // same as ^ but k
239  RT kd = k_in - kl;
240 
241  // interpolated value at (i*, j*, k_in)
242  RT * F_i_j_kd = new RT[16];
243  for(IT i=0; i<4; ++i)
244  for(IT j=0; j<4; ++j)
245  F_i_j_kd[i*4+j] = CINT(kd,
246  _array[idx(il+i-1, jl+j-1, kl-1)], _array[idx(il+i-1, jl+j-1, kl+0)],
247  _array[idx(il+i-1, jl+j-1, kl+1)], _array[idx(il+i-1, jl+j-1, kl+2)]);
248 
249  // interpolated value at (i*, j_in, k_in)
250  RT * F_i_jd_kd = new RT[4];
251  for(IT i=0; i<4; ++i)
252  F_i_jd_kd[i] = CINT(jd, F_i_j_kd[i*4+0], F_i_j_kd[i*4+1], F_i_j_kd[i*4+2], F_i_j_kd[i*4+3]);
253 
254  // interpolated value at (i_in, j_in, k_in)
255  RT Fijk = CINT(id, F_i_jd_kd[0], F_i_jd_kd[1], F_i_jd_kd[2], F_i_jd_kd[3]);
256 
257  delete [] F_i_j_kd;
258  delete [] F_i_jd_kd;
259 
260  return Fijk;
261  }
262 };
263 
264 template <class T>
265 void cosmoArraySwap(T & arr1, T & arr2)
266 {
267  std::swap(arr1.nx, arr2.nx);
268  std::swap(arr1.ny, arr2.ny);
269  std::swap(arr1.nz, arr2.nz);
270  std::swap(arr1.pts, arr2.pts);
271  std::swap(arr1.name, arr2.name);
272  std::swap(arr1._array, arr2._array);
273 }
274 
275 }
276 
277 #endif
Definition: Array.h:14
Definition: bardeen.cc:5