ExaDG
Loading...
Searching...
No Matches
spectrum.h
1/* ______________________________________________________________________
2 *
3 * ExaDG - High-Order Discontinuous Galerkin for the Exa-Scale
4 *
5 * Copyright (C) 2021 by the ExaDG authors
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
19 * ______________________________________________________________________
20 */
21
22#ifndef DEAL_SPECTRUM_SPECTRUM
23#define DEAL_SPECTRUM_SPECTRUM
24
25#include <fftw3-mpi.h>
26#include <mpi.h>
27#include <cmath>
28
29// ExaDG
30#include <exadg/postprocessor/spectral_analysis/setup.h>
31
32// shortcuts for accessing linearized arrays
33#define u_comp2(i, j) u_comp[(j - local_start) * (N / 2 + 1) + i]
34#define v_comp2(i, j) v_comp[(j - local_start) * (N / 2 + 1) + i]
35#define u_comp3(i, j, k) u_comp[((k - local_start) * N + j) * (N / 2 + 1) + i]
36#define v_comp3(i, j, k) v_comp[((k - local_start) * N + j) * (N / 2 + 1) + i]
37#define w_comp3(i, j, k) w_comp[((k - local_start) * N + j) * (N / 2 + 1) + i]
38
39namespace dealspectrum
40{
45{
46 MPI_Comm const comm;
47
48 // reference to DEAL.SPECTRUM setup
49 Setup & s;
50 // is initialized?
51 bool initialized;
52 // rank of process which owns row
53 int * _indices_proc_rows;
54
55public:
60 SpectralAnalysis(MPI_Comm const & comm, Setup & s) : comm(comm), s(s), initialized(false)
61 {
62 }
63
70 inline int
72 {
73 return _indices_proc_rows[i];
74 }
75
82 void
83 getLocalRange(int & start, int & end)
84 {
85 start = local_start;
86 end = local_end;
87 }
88
92 void
94 {
95 // check if already initialized
96 if(this->initialized)
97 return;
98 this->initialized = true;
99
100 // extract settings
101 this->N = s.cells * s.points_dst;
102 this->dim = s.dim;
103 this->rank = s.rank;
104 this->size = s.size;
105 this->bins = s.bins;
106
107 // setup global size of output arrays...
108 n = new ptrdiff_t[dim];
109 for(int i = 0; i < dim - 1; i++)
110 n[i] = N;
111 n[dim - 1] = N / 2 + 1;
112
113 // ...get local size of local output arrays
114 ptrdiff_t local_elements = 0;
115 alloc_local = fftw_mpi_local_size(dim, n, comm, &local_elements, &local_start);
116 local_end = local_start + local_elements;
117
118 // determine how many rows each process has
119 int * global_elements = new int[size];
120 MPI_Allgather(&local_elements, 1, MPI_INTEGER, global_elements, 1, MPI_INTEGER, comm);
121
122 // ... save for each row by whom it is owned
123 _indices_proc_rows = new int[N];
124
125 for(int i = 0, c = 0; i < size; i++)
126 for(int j = 0; j < global_elements[i]; j++, c++)
127 _indices_proc_rows[c] = i;
128
129 // ... clean up
130 delete[] global_elements;
131
132 // modify global size for input array
133 n[dim - 1] = N;
134
135 // allocate memory
136 // ... for input array (real) - allocated together for all directions
137 u_real = fftw_alloc_real(2 * alloc_local * dim);
138 // ... and save required size
139 this->bsize = 2 * alloc_local;
140
141 // initialize input array with zero (not needed: only useful for IO -> hard zero)
142 for(int i = 0; i < 2 * alloc_local * dim; i++)
143 u_real[i] = 0;
144
145 // set pointer for v input field
146 v_real = u_real + 2 * alloc_local;
147
148 // allocate memory for output array (complex)
149 u_comp = fftw_alloc_complex(alloc_local);
150 v_comp = fftw_alloc_complex(alloc_local);
151
152 // do the same for 3D
153 if(dim == 3)
154 {
155 w_real = v_real + 2 * alloc_local;
156 w_comp = fftw_alloc_complex(alloc_local);
157 }
158
159 // allocate memory and ...
160 this->e = new double[N];
161 this->E = new double[N];
162 this->k = new double[N];
163 this->K = new double[N];
164 this->c = new double[N];
165 this->C = new double[N];
166 }
167
172 {
173 // not initialized -> nothing to clean up
174 if(not initialized)
175 return;
176
177 // free data structures
178 delete[] _indices_proc_rows;
179
180 free(n);
181 fftw_free(u_comp);
182 fftw_free(v_comp);
183 free(u_real);
184
185 if(dim == 3)
186 {
187 fftw_free(w_comp);
188 }
189
190 delete e;
191 delete E;
192 delete k;
193 delete K;
194 delete c;
195 delete C;
196 }
197
201 void
203 {
204 // perform FFT for u
205 fftw_plan pu = fftw_mpi_plan_dft_r2c(dim, n, u_real, u_comp, comm, FFTW_ESTIMATE);
206 fftw_execute(pu);
207 fftw_destroy_plan(pu);
208
209 // ... for v
210 fftw_plan pv = fftw_mpi_plan_dft_r2c(dim, n, v_real, v_comp, comm, FFTW_ESTIMATE);
211 fftw_execute(pv);
212 fftw_destroy_plan(pv);
213
214 // ... for w
215 if(dim == 3)
216 {
217 fftw_plan pw = fftw_mpi_plan_dft_r2c(dim, n, w_real, w_comp, comm, FFTW_ESTIMATE);
218 fftw_execute(pw);
219 fftw_destroy_plan(pw);
220 }
221 }
222
223 void
224 calculate_energy()
225 {
226 double scaling = pow(N, dim);
227 double e_physical = 0.0, e_spectral = 0.0;
228
229 for(int i = 0; i < 2 * alloc_local * dim; i++)
230 {
231 e_physical += u_real[i] * u_real[i];
232 }
233
234 // scale: integrate cell wise...
235 e_physical /= pow(N, dim);
236 // ... and make to energy 0.5*u^2
237 e_physical *= 0.5;
238
239 if(dim == 2)
240 {
241 for(int j = local_start; j < local_end; j++)
242 {
243 for(int i = 0; i < N; i++)
244 {
245 e_spectral += u_comp2(MIN(i, N - i), j)[0] * u_comp2(MIN(i, N - i), j)[0] +
246 u_comp2(MIN(i, N - i), j)[1] * u_comp2(MIN(i, N - i), j)[1] +
247 v_comp2(MIN(i, N - i), j)[0] * v_comp2(MIN(i, N - i), j)[0] +
248 v_comp2(MIN(i, N - i), j)[1] * v_comp2(MIN(i, N - i), j)[1];
249 }
250 }
251 }
252 else if(dim == 3)
253 {
254 for(int k_ = local_start; k_ < local_end; k_++)
255 {
256 for(int j = 0; j < N; j++)
257 {
258 for(int i = 0; i < N; i++)
259 {
260 e_spectral += u_comp3(MIN(i, N - i), j, k_)[0] * u_comp3(MIN(i, N - i), j, k_)[0] +
261 u_comp3(MIN(i, N - i), j, k_)[1] * u_comp3(MIN(i, N - i), j, k_)[1] +
262 v_comp3(MIN(i, N - i), j, k_)[0] * v_comp3(MIN(i, N - i), j, k_)[0] +
263 v_comp3(MIN(i, N - i), j, k_)[1] * v_comp3(MIN(i, N - i), j, k_)[1] +
264 w_comp3(MIN(i, N - i), j, k_)[0] * w_comp3(MIN(i, N - i), j, k_)[0] +
265 w_comp3(MIN(i, N - i), j, k_)[1] * w_comp3(MIN(i, N - i), j, k_)[1];
266 }
267 }
268 }
269 }
270 else
271 {
272 AssertThrow(false, dealii::ExcMessage("Not implemented."));
273 }
274
275 // scale: due to FFT...
276 e_spectral /= scaling * scaling;
277 // ... and make to energy 0.5*u^2
278 e_spectral *= 0.5;
279
280 MPI_Reduce(&e_physical, &this->e_d, 1, MPI_DOUBLE, MPI_SUM, 0, comm);
281 MPI_Reduce(&e_spectral, &this->e_s, 1, MPI_DOUBLE, MPI_SUM, 0, comm);
282 }
283
287 void
289 {
290 double scaling = pow(N, dim);
291
292 // ... init with zero
293 for(int i = 0; i < N; i++)
294 {
295 e[i] = 0;
296 k[i] = 0;
297 c[i] = 0;
298 }
299
300 // collect energy for local domain...
301 if(dim == 2)
302 {
303 for(int j = local_start; j < local_end; j++)
304 {
305 for(int i = 0; i < N; i++)
306 {
307 // determine wavenumber...
308 double r = sqrt(pow(MIN(i, N - i), 2.0) + pow(MIN(j, N - j), 2.0));
309 // ... use for binning
310 int p = static_cast<int>(std::round(r));
311 // ... update energy
312 e[p] += u_comp2(MIN(i, N - i), j)[0] * u_comp2(MIN(i, N - i), j)[0] +
313 u_comp2(MIN(i, N - i), j)[1] * u_comp2(MIN(i, N - i), j)[1] +
314 v_comp2(MIN(i, N - i), j)[0] * v_comp2(MIN(i, N - i), j)[0] +
315 v_comp2(MIN(i, N - i), j)[1] * v_comp2(MIN(i, N - i), j)[1];
316
317 // ... update kappa results
318 k[p] += r;
319 c[p]++;
320 }
321 }
322 }
323 else if(dim == 3)
324 {
325 for(int k_ = local_start; k_ < local_end; k_++)
326 {
327 for(int j = 0; j < N; j++)
328 {
329 for(int i = 0; i < N; i++)
330 {
331 // determine wavenumber...
332 double r =
333 sqrt(pow(MIN(i, N - i), 2.0) + pow(MIN(j, N - j), 2.0) + pow(MIN(k_, N - k_), 2.0));
334 // ... use for binning
335 int p = static_cast<int>(std::round(r));
336 // ... update energy
337 e[p] += u_comp3(MIN(i, N - i), j, k_)[0] * u_comp3(MIN(i, N - i), j, k_)[0] +
338 u_comp3(MIN(i, N - i), j, k_)[1] * u_comp3(MIN(i, N - i), j, k_)[1] +
339 v_comp3(MIN(i, N - i), j, k_)[0] * v_comp3(MIN(i, N - i), j, k_)[0] +
340 v_comp3(MIN(i, N - i), j, k_)[1] * v_comp3(MIN(i, N - i), j, k_)[1] +
341 w_comp3(MIN(i, N - i), j, k_)[0] * w_comp3(MIN(i, N - i), j, k_)[0] +
342 w_comp3(MIN(i, N - i), j, k_)[1] * w_comp3(MIN(i, N - i), j, k_)[1];
343
344 // ... update kappa results
345 k[p] += r;
346 c[p]++;
347 }
348 }
349 }
350 }
351
352 // ... sum up local results to global result
353 MPI_Reduce(e, E, N, MPI_DOUBLE, MPI_SUM, 0, comm);
354 MPI_Reduce(k, K, N, MPI_DOUBLE, MPI_SUM, 0, comm);
355 MPI_Reduce(c, C, N, MPI_DOUBLE, MPI_SUM, 0, comm);
356
357 // ... normalize results
358 for(int i = 0; i < N; i++)
359 {
360 // ... average energy and kappa
361 K[i] /= C[i];
362 // ... factor from fft
363 E[i] /= scaling * scaling;
364 // ... and make to energy 0.5*u^2
365 E[i] *= 0.5;
366 }
367 }
368
376 int
377 get_results(double *& K, double *& E, double *& C, double & e_d, double & e_s)
378 {
379 K = this->K;
380 E = this->E;
381 C = this->C;
382 e_d = this->e_d;
383 e_s = this->e_s;
384 return N / 2 + 1;
385 }
386
392 void
393 serialize(char const * filename)
394 {
395 int start = local_start;
396 int end = local_end;
397 int delta = 2 * (N / 2 + 1) * dealii::Utilities::pow(N, dim - 2);
398 int delta_all = 2 * (N / 2 + 1) * dealii::Utilities::pow(N, dim - 1) * sizeof(double);
399
400 //
401 int dofs = (end - start) * delta;
402 MPI_Offset disp = 8 * sizeof(int) + start * delta * sizeof(double); // bytes
403
404 // create view
405 MPI_Datatype stype;
406 MPI_Type_contiguous(dofs, MPI_DOUBLE, &stype);
407 MPI_Type_commit(&stype);
408
409 // read file
410 MPI_File fh;
411 MPI_File_open(comm, filename, MPI_MODE_WRONLY, MPI_INFO_NULL, &fh);
412
413 MPI_File_set_view(fh, disp + delta_all * 0, MPI_DOUBLE, MPI_DOUBLE, "native", MPI_INFO_NULL);
414 MPI_File_write_all(fh, u_real, dofs, MPI_DOUBLE, MPI_STATUSES_IGNORE);
415
416 MPI_File_set_view(fh, disp + delta_all * 1, MPI_DOUBLE, MPI_DOUBLE, "native", MPI_INFO_NULL);
417 MPI_File_write_all(fh, v_real, dofs, MPI_DOUBLE, MPI_STATUSES_IGNORE);
418
419 if(dim == 3)
420 {
421 MPI_File_set_view(fh, disp + delta_all * 2, MPI_DOUBLE, MPI_DOUBLE, "native", MPI_INFO_NULL);
422 MPI_File_write_all(fh, w_real, dofs, MPI_DOUBLE, MPI_STATUSES_IGNORE);
423 }
424
425 MPI_File_close(&fh);
426 MPI_Type_free(&stype);
427 }
428
434 void
435 deserialize(char *& filename)
436 {
437 int start = local_start;
438 int end = local_end;
439 int delta = 2 * (N / 2 + 1) * dealii::Utilities::pow(N, dim - 2);
440 int delta_all = 2 * (N / 2 + 1) * dealii::Utilities::pow(N, dim - 1) * sizeof(double);
441
442 //
443 int dofs = (end - start) * delta;
444 MPI_Offset disp = 8 * sizeof(int) + start * delta * sizeof(double); // bytes
445
446 // create view
447 MPI_Datatype stype;
448 MPI_Type_contiguous(dofs, MPI_DOUBLE, &stype);
449 MPI_Type_commit(&stype);
450
451 // read file
452 MPI_File fh;
453 MPI_File_open(comm, filename, MPI_MODE_RDONLY, MPI_INFO_NULL, &fh);
454
455 MPI_File_set_view(fh, disp + delta_all * 0, MPI_DOUBLE, MPI_DOUBLE, "native", MPI_INFO_NULL);
456 MPI_File_read_all(fh, u_real, dofs, MPI_DOUBLE, MPI_STATUSES_IGNORE);
457
458 MPI_File_set_view(fh, disp + delta_all * 1, MPI_DOUBLE, MPI_DOUBLE, "native", MPI_INFO_NULL);
459 MPI_File_read_all(fh, v_real, dofs, MPI_DOUBLE, MPI_STATUSES_IGNORE);
460
461 if(dim == 3)
462 {
463 MPI_File_set_view(fh, disp + delta_all * 2, MPI_DOUBLE, MPI_DOUBLE, "native", MPI_INFO_NULL);
464 MPI_File_read_all(fh, w_real, dofs, MPI_DOUBLE, MPI_STATUSES_IGNORE);
465 }
466
467 MPI_File_close(&fh);
468 MPI_Type_free(&stype);
469 }
470
471private:
472 // number of dofs in each direction
473 int N;
474 // dimensions
475 int dim;
476 // rank of this process
477 int rank;
478 // number of processes
479 int size;
480 // bin count
481 int bins;
482 // number of dofs in each direction (for FFTW)
483 ptrdiff_t * n;
484 // local row/plane range: start
485 ptrdiff_t local_start;
486 // ... end
487 ptrdiff_t local_end;
488 ptrdiff_t alloc_local;
489
490public:
491 // size of each real field
492 int bsize;
493 // real field for u
494 double * u_real;
495
496private:
497 // ... for v
498 double * v_real;
499 // ... for w
500 double * w_real;
501 // complex field for u
502 fftw_complex * u_comp;
503 // ... for v
504 fftw_complex * v_comp;
505 // ... for w
506 fftw_complex * w_comp;
507
508private:
509 // array for locally collecting energy
510 double * e;
511 // ... kappa
512 double * k;
513 // ... kappa count
514 double * c;
515 // array for globally collecting energy (on rank 0)
516 double * E;
517 // ... kappa
518 double * K;
519 // ... kappa count
520 double * C;
521 double e_d;
522 double e_s;
523};
524
525} // namespace dealspectrum
526
527#endif
Definition setup.h:56
Definition spectrum.h:45
~SpectralAnalysis()
Definition spectrum.h:171
void calculate_energy_spectrum()
Definition spectrum.h:288
SpectralAnalysis(MPI_Comm const &comm, Setup &s)
Definition spectrum.h:60
void init()
Definition spectrum.h:93
void deserialize(char *&filename)
Definition spectrum.h:435
void serialize(char const *filename)
Definition spectrum.h:393
int get_results(double *&K, double *&E, double *&C, double &e_d, double &e_s)
Definition spectrum.h:377
int indices_proc_rows(int i)
Definition spectrum.h:71
void execute()
Definition spectrum.h:202
void getLocalRange(int &start, int &end)
Definition spectrum.h:83