49#include "../COMM/mpioverride.h"
50#include "../INCLUDE/maiaconstants.h"
51#include "../INCLUDE/maiatypes.h"
52#include "../IO/context.h"
53#include "../MEMORY/scratch.h"
62 return (
a[0] *
b[1] * c[0] +
a[1] *
b[0] * c[0] -
a[0] *
b[0] * c[1] +
a[1] *
b[1] * c[1]);
85 const MBool computeNabla2P =
false) {
86 DEBUG(
"initFft entry", MAIA_DEBUG_TRACE_IN);
88 const MInt size = nx * ny * nz;
89 const ptrdiff_t rank = 3;
90 const MInt howmany = 3;
91 if(nx % 2 != 0 || ny % 2 != 0 || nz % 2 != 0) {
92 std::stringstream errorMessage;
93 errorMessage <<
" FFTInit: domainsize must NOT be an odd number! " << nx <<
" " << ny <<
" " << nz << std::endl;
94 mTerm(1, AT_, errorMessage.str());
97 m_log <<
" --- initializing FFTW --- " << std::endl;
98 m_log <<
" domain size = " << nx <<
"x" << ny <<
"x" << nz << std::endl;
102 MPI_Comm_rank(comm, &domainId);
103 MPI_Comm_size(comm, &noDomains);
104 MPI_Comm MPI_COMM_FFTW;
106 maxRank =
mMin(nz, noDomains);
107 while(nz % maxRank != 0) {
111 MInt color = (domainId < maxRank) ? 0 : MPI_UNDEFINED;
112 MPI_Comm_split(comm, color, domainId, &MPI_COMM_FFTW, AT_,
"MPI_COMM_FFTW");
113 m_log <<
"no ranks for fft: " << maxRank << std::endl;
116 ptrdiff_t alloc_local, local_n0, local_0_start;
117 ptrdiff_t alloc_localP, local_n0P, local_0_startP;
118 ptrdiff_t alloc_localTmp, tmpLocal_n0, tmpLocal_0_start;
120 const ptrdiff_t n[3] = {nx, ny, nz};
122 alloc_local = (domainId < maxRank) ? fftw_mpi_local_size_many(rank, n, howmany, FFTW_MPI_DEFAULT_BLOCK, MPI_COMM_FFTW,
123 &local_n0, &local_0_start)
125 alloc_localTmp = (domainId < maxRank) ? fftw_mpi_local_size_many(rank, n, tmpHowMany, FFTW_MPI_DEFAULT_BLOCK,
126 MPI_COMM_FFTW, &tmpLocal_n0, &tmpLocal_0_start)
128 alloc_localP = (domainId < maxRank) ? fftw_mpi_local_size_many(rank, n, 1, FFTW_MPI_DEFAULT_BLOCK, MPI_COMM_FFTW,
129 &local_n0P, &local_0_startP)
133 fftInfo[0] = maxRank;
134 fftInfo[1] = (domainId < maxRank) ? local_n0 : 0;
135 fftInfo[2] = (domainId < maxRank) ? local_0_start : size;
136 fftInfo[3] = (domainId < maxRank) ? alloc_local : 3;
150 static const MInt referenceCubeSize =
151 ((
Context::propertyExists(
"referenceCubeSize")) ? Context::getBasicProperty<MInt>(
"referenceCubeSize", AT_) : 1);
157 static const int64_t seed0 = (int64_t)(
158 (
Context::propertyExists(
"randomDeviceSeed")) ? Context::getBasicProperty<MFloat>(
"randomDeviceSeed", AT_) : -1);
160 static MUlong seed = (unsigned)((seed0 > -1) ? seed0 : std::random_device()());
161 MPI_Bcast(&seed, 1, MPI_UNSIGNED_LONG, 0, comm, AT_,
"seed");
162 std::mt19937_64 gen(seed);
163 std::normal_distribution<> distr(F0, F1);
165 uPhysField = (fftw_complex*)fftw_malloc(alloc_local *
sizeof(fftw_complex));
167 if(computeNabla2P) nabla2P = (fftw_complex*)fftw_malloc(alloc_localP *
sizeof(fftw_complex));
169 if(domainId < maxRank) {
170 ptrdiff_t rSlice_0_start = nx - (
MInt)local_0_start - (
MInt)local_n0 + 1;
179 fftw_complex* hatField = uPhysField;
180 fftw_complex* tmpHat = &tmpHatFieldMem[0];
183 fftw_plan plan = fftw_mpi_plan_many_dft(rank, n, howmany, FFTW_MPI_DEFAULT_BLOCK, FFTW_MPI_DEFAULT_BLOCK, hatField,
184 hatField, MPI_COMM_FFTW, FFTW_BACKWARD, FFTW_ESTIMATE);
185 fftw_plan tmpPlan = fftw_mpi_plan_many_dft(rank, n, tmpHowMany, FFTW_MPI_DEFAULT_BLOCK, FFTW_MPI_DEFAULT_BLOCK,
186 tmpHat, tmpHat, MPI_COMM_FFTW, FFTW_BACKWARD, FFTW_ESTIMATE);
192 m_log <<
"random device seed is " << seed << std::endl;
194 (nx <= 256) ? 256 : nx;
195 for(
MInt k0 = -refSize / 2 + 1; k0 <= refSize / 2; k0++) {
196 for(
MInt k1 = -refSize / 2 + 1; k1 <= refSize / 2; k1++) {
197 for(
MInt k2 = -refSize / 2 + 1; k2 <= refSize / 2; k2++) {
198 if(k0 < -nx / 2 + 1 || k0 > nx / 2 || k1 < -ny / 2 + 1 || k1 > ny / 2 || k2 < -nz / 2 + 1 || k2 > nz / 2) {
206 mTerm(1, AT_,
"wrong refSize.");
211 MInt i0 = (k0 >= 0) ? k0 : k0 + nx;
212 MInt i1 = (k1 >= 0) ? k1 : k1 + ny;
213 MInt i2 = (k2 >= 0) ? k2 : k2 + nz;
215 MInt localrPos = pos - (((
MInt)rSlice_0_start) * ny * nz);
216 MInt localPos = pos - (((
MInt)local_0_start) * ny * nz);
219 if(pos >= ((
MInt)local_0_start) * nz * ny && pos < ((
MInt)(local_0_start + local_n0) * ny * nz)) {
220 if(localPos >= ny * nz * local_n0 || localPos < 0) {
221 mTerm(1, AT_,
"index exceeds array(1a)");
223 uHatField[localPos][0] = distr(gen);
224 uHatField[localPos][1] = distr(gen);
225 vHatField[localPos][0] = distr(gen);
226 vHatField[localPos][1] = distr(gen);
227 wHatField[localPos][0] = distr(gen);
228 wHatField[localPos][1] = distr(gen);
231 if(pos >= ((
MInt)rSlice_0_start) * nz * ny && pos < ((
MInt)(rSlice_0_start + local_n0) * ny * nz) && i0 != 0
233 localrPos = pos - (((
MInt)rSlice_0_start) * ny * nz);
234 if(localrPos >= ny * nz * local_n0 || localrPos < 0) {
235 mTerm(1, AT_,
"index exceeds array(1c)");
237 ruHatField[localrPos][0] = distr(gen);
238 ruHatField[localrPos][1] = distr(gen);
239 rvHatField[localrPos][0] = distr(gen);
240 rvHatField[localrPos][1] = distr(gen);
241 rwHatField[localrPos][0] = distr(gen);
242 rwHatField[localrPos][1] = distr(gen);
245 if(!(pos >= ((
MInt)local_0_start) * nz * ny && pos < ((
MInt)(local_0_start + local_n0) * ny * nz))
246 && !(pos >= ((
MInt)rSlice_0_start) * nz * ny && pos < ((
MInt)(rSlice_0_start + local_n0) * ny * nz)
247 && i0 != 0 && i0 != nx / 2)) {
248 for(
MInt k = 0; k < howmany; k++) {
257 const MFloat kMin = F2 * PI / referenceCubeSize;
258 const MFloat kp = kpRatio * kMin * referenceCubeSize;
264 for(
MInt i0 = (
MInt)local_0_start; i0 < (
MInt)(local_0_start + local_n0); i0++) {
265 for(
MInt i1 = 0; i1 < ny; i1++) {
266 for(
MInt i2 = 0; i2 < nz; i2++) {
268 MInt j0 = (i0 > nx / 2) ? i0 - nx : i0;
269 MInt j1 = (i1 > ny / 2) ? i1 - ny : i1;
270 MInt j2 = (i2 > nz / 2) ? i2 - nz : i2;
274 if(kMinSpec > 0 && kMaxSpec > 0) {
275 if(j0 > kMaxSpec || j0 < kMinSpec) j0 = 0;
276 if(j1 > kMaxSpec || j1 < kMinSpec) j1 = 0;
277 if(j2 > kMaxSpec || j2 < kMinSpec) j2 = 0;
279 k[0] = ((
MFloat)j0) * kMin;
280 k[1] = ((
MFloat)j1) * kMin;
281 k[2] = ((
MFloat)j2) * kMin;
284 MInt rpos = ((nz - i2) % nz) + nz * (((ny - i1) % ny) + ny * ((nx - i0) % nx));
285 MInt localPos = pos - (((
MInt)local_0_start) * ny * nz);
286 MInt localrPos = rpos - (((
MInt)rSlice_0_start) * ny * nz);
287 ASSERT(pos > -1 && pos < size && rpos > -1 && rpos < size,
"");
289 MFloat kAbs = sqrt(k[0] * k[0] + k[1] * k[1] + k[2] * k[2]);
294 hatField[howmany * localPos][0] = F0;
295 hatField[howmany * localPos][1] = F0;
296 hatField[howmany * localPos + 1][0] = F0;
297 hatField[howmany * localPos + 1][1] = F0;
298 hatField[howmany * localPos + 2][0] = F0;
299 hatField[howmany * localPos + 2][1] = F0;
306 energy = pow(kAbs / kp, 4.0) * exp(-2.0 * (kAbs / kp) * (kAbs / kp));
310 energy =
POW2(kAbs / kp) * exp(-F1B2 *
POW2(kAbs / kp));
315 energy = F3B2 * (kAbs /
POW2(kp)) * exp(-kAbs / kp);
319 mTerm(1, AT_,
"Unknown spectrum.");
324 if(j0 > 0 && j1 == 0 && j2 == 0) {
327 eps += F2 * dk *
POW2(k[0]) * energy;
328 length += F1B2 * PI * dk * energy / k[0];
333 const MFloat fac = PI * sqrt(energy) / (sqrt(referenceCubeSize * F2) * referenceCubeSize * kAbs);
335 if(i0 == 0 || i0 == nx / 2) {
336 localrPos = rpos - (((
MInt)local_0_start) * ny * nz);
337 r[0] = fac * (uHatField[localPos][0] + uHatField[localrPos][0]);
338 s[0] = fac * (uHatField[localPos][1] - uHatField[localrPos][1]);
339 r[1] = fac * (vHatField[localPos][0] + vHatField[localrPos][0]);
340 s[1] = fac * (vHatField[localPos][1] - vHatField[localrPos][1]);
341 r[2] = fac * (wHatField[localPos][0] + wHatField[localrPos][0]);
342 s[2] = fac * (wHatField[localPos][1] - wHatField[localrPos][1]);
344 if(localPos >= ny * nz * local_n0 || localrPos >= ny * nz * local_n0 || localPos < 0 || localrPos < 0) {
345 mTerm(1, AT_,
"index exceeds array(2)");
347 r[0] = fac * (uHatField[localPos][0] + ruHatField[localrPos][0]);
348 s[0] = fac * (uHatField[localPos][1] - ruHatField[localrPos][1]);
349 r[1] = fac * (vHatField[localPos][0] + rvHatField[localrPos][0]);
350 s[1] = fac * (vHatField[localPos][1] - rvHatField[localrPos][1]);
351 r[2] = fac * (wHatField[localPos][0] + rwHatField[localrPos][0]);
352 s[2] = fac * (wHatField[localPos][1] - rwHatField[localrPos][1]);
356 hatField[howmany * localPos][0] = (1.0 - k[0] * k[0] / (kAbs * kAbs)) * r[0]
357 - k[0] * k[1] / (kAbs * kAbs) * r[1] - k[0] * k[2] / (kAbs * kAbs) * r[2];
358 hatField[howmany * localPos][1] = (1.0 - k[0] * k[0] / (kAbs * kAbs)) * s[0]
359 - k[0] * k[1] / (kAbs * kAbs) * s[1] - k[0] * k[2] / (kAbs * kAbs) * s[2];
361 hatField[howmany * localPos + 1][0] = -k[1] * k[0] / (kAbs * kAbs) * r[0]
362 + (1.0 - k[1] * k[1] / (kAbs * kAbs)) * r[1]
363 - k[1] * k[2] / (kAbs * kAbs) * r[2];
364 hatField[howmany * localPos + 1][1] = -k[1] * k[0] / (kAbs * kAbs) * s[0]
365 + (1.0 - k[1] * k[1] / (kAbs * kAbs)) * s[1]
366 - k[1] * k[2] / (kAbs * kAbs) * s[2];
368 hatField[howmany * localPos + 2][0] = -k[2] * k[0] / (kAbs * kAbs) * r[0] - k[2] * k[1] / (kAbs * kAbs) * r[1]
369 + (1.0 - k[2] * k[2] / (kAbs * kAbs)) * r[2];
370 hatField[howmany * localPos + 2][1] = -k[2] * k[0] / (kAbs * kAbs) * s[0] - k[2] * k[1] / (kAbs * kAbs) * s[1]
371 + (1.0 - k[2] * k[2] / (kAbs * kAbs)) * s[2];
376 for(
MInt i = 0; i < local_n0 * nz * ny; i++) {
377 if(i >= alloc_local / 3)
mTerm(1, AT_,
"index exceeds array(6)");
383 for(
MInt i = 0; i < 3; i++) {
384 for(
MInt j = i; j < 3; j++) {
385 for(
MInt i0 = (
MInt)tmpLocal_0_start; i0 < (
MInt)(tmpLocal_0_start + tmpLocal_n0); i0++) {
386 for(
MInt i1 = 0; i1 < ny; i1++) {
387 for(
MInt i2 = 0; i2 < nz; i2++) {
389 MInt j0 = (i0 > nx / 2) ? i0 - nx : i0;
390 MInt j1 = (i1 > ny / 2) ? i1 - ny : i1;
391 MInt j2 = (i2 > nz / 2) ? i2 - nz : i2;
392 k[0] = ((
MFloat)j0) * kMin;
393 k[1] = ((
MFloat)j1) * kMin;
394 k[2] = ((
MFloat)j2) * kMin;
396 MInt localPos = pos - (((
MInt)tmpLocal_0_start) * ny * nz);
397 if(localPos * tmpHowMany + tmpHowMany - 1 >= alloc_localTmp)
mTerm(1, AT_,
"index exceeds array(3)");
398 const MInt dimIndex0 = (i == 0) ? 0 : ((i == 1) ? 1 : 2);
399 const MInt dimIndex1 = (j == 0) ? 0 : ((j == 1) ? 1 : 2);
400 tmpHat[localPos * tmpHowMany][0] = -k[j] * hatField[howmany * localPos + dimIndex0][1];
401 tmpHat[localPos * tmpHowMany][1] = k[j] * hatField[howmany * localPos + dimIndex0][0];
402 tmpHat[localPos * tmpHowMany + 1][0] = -k[i] * hatField[howmany * localPos + dimIndex1][1];
403 tmpHat[localPos * tmpHowMany + 1][1] = k[i] * hatField[howmany * localPos + dimIndex1][0];
408 fftw_execute(tmpPlan);
409 MFloat fac = (i == j) ? F1 : F2;
411 for(
MInt i0 = (
MInt)tmpLocal_0_start; i0 < (
MInt)(tmpLocal_0_start + tmpLocal_n0); i0++) {
412 for(
MInt i1 = 0; i1 < ny; i1++) {
413 for(
MInt i2 = 0; i2 < nz; i2++) {
415 MInt localPos = pos - (((
MInt)tmpLocal_0_start) * ny * nz);
416 if(localPos * tmpHowMany + tmpHowMany - 1 >= alloc_localTmp)
mTerm(1, AT_,
"index exceeds array(4)");
417 if(localPos >= alloc_local / 3)
mTerm(1, AT_,
"index exceeds array(5)");
418 nabla2P[localPos][0] += fac * tmpHat[localPos * tmpHowMany][0] * tmpHat[localPos * tmpHowMany + 1][0];
419 tmpHat[localPos * tmpHowMany][0] = 0;
420 tmpHat[localPos * tmpHowMany][1] = 0;
421 tmpHat[localPos * tmpHowMany + 1][0] = 0;
422 tmpHat[localPos * tmpHowMany + 1][1] = 0;
429 fftw_destroy_plan(tmpPlan);
431 for(
MInt i = 0; i < local_n0 * nz * ny; i++) {
432 if(i >= alloc_local / 3)
mTerm(1, AT_,
"index exceeds array(6)");
436 fftw_plan planP = fftw_mpi_plan_many_dft(rank, n, 1, FFTW_MPI_DEFAULT_BLOCK, FFTW_MPI_DEFAULT_BLOCK, nabla2P,
437 nabla2P, MPI_COMM_FFTW, FFTW_FORWARD, FFTW_ESTIMATE);
440 for(
MInt k = 0; k < local_n0 * nz * ny; k++) {
441 if(k >= alloc_local / 3)
mTerm(1, AT_,
"index exceeds array(7)");
442 nabla2P[k][0] /= ((
MFloat)size);
443 nabla2P[k][1] /= ((
MFloat)size);
446 fftw_destroy_plan(planP);
447 for(
MInt i0 = (
MInt)local_0_start; i0 < (
MInt)(local_0_start + local_n0); i0++) {
448 for(
MInt i1 = 0; i1 < ny; i1++) {
449 for(
MInt i2 = 0; i2 < nz; i2++) {
451 MInt j0 = (i0 > nx / 2) ? i0 - nx : i0;
452 MInt j1 = (i1 > ny / 2) ? i1 - ny : i1;
453 MInt j2 = (i2 > nz / 2) ? i2 - nz : i2;
454 k[0] = ((
MFloat)j0) * kMin;
455 k[1] = ((
MFloat)j1) * kMin;
456 k[2] = ((
MFloat)j2) * kMin;
458 MInt localPos = pos - (((
MInt)local_0_start) * ny * nz);
459 MFloat k2 = k[0] * k[0] + k[1] * k[1] + k[2] * k[2];
460 if(localPos >= alloc_local / 3)
mTerm(1, AT_,
"index exceeds array(8)");
462 nabla2P[localPos][0] = F0;
463 nabla2P[localPos][1] = F0;
466 nabla2P[localPos][0] = nabla2P[localPos][0] / k2;
467 nabla2P[localPos][1] = nabla2P[localPos][1] / k2;
473 fftw_plan planP2 = fftw_mpi_plan_many_dft(rank, n, 1, FFTW_MPI_DEFAULT_BLOCK, FFTW_MPI_DEFAULT_BLOCK, nabla2P,
474 nabla2P, MPI_COMM_FFTW, FFTW_BACKWARD, FFTW_ESTIMATE);
475 fftw_execute(planP2);
476 fftw_destroy_plan(planP2);
479 MPI_Allreduce(MPI_IN_PLACE, &eng, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_FFTW, AT_,
"MPI_IN_PLACE",
"eng");
480 MPI_Allreduce(MPI_IN_PLACE, &eps, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_FFTW, AT_,
"MPI_IN_PLACE",
"eps");
481 MPI_Allreduce(MPI_IN_PLACE, &length, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_FFTW, AT_,
"MPI_IN_PLACE",
"length");
484 std::cerr <<
"SPECTRUM: kinetic energy: " << eng <<
" (theoretical: 1.5)"
485 <<
", dissipation rate: " << eps <<
" (theoretical: " << 72.0 *
POW2(kpRatio * PI) <<
")"
486 <<
", integral length/unit length: " << length <<
" (theoretical: " << F3B8 / kpRatio <<
")"
491 m_log <<
"fft finished" << std::endl;
495 DEBUG(
"initFft return", MAIA_DEBUG_TRACE_OUT);
505 static MBool deviateAvailable =
false;
506 static float storedDeviate;
507 MFloat polar, rsquared, var1, var2;
512 if(!deviateAvailable) {
518 rsquared = var1 * var1 + var2 * var2;
519 }
while(rsquared >= 1.0 ||
approx(rsquared, 0.0, MFloatEps));
522 polar = sqrt(-2.0 * log(rsquared) / rsquared);
525 storedDeviate = var1 * polar;
526 deviateAvailable =
true;
530 return var2 * polar * sigma + mu;
536 deviateAvailable =
false;
538 return storedDeviate * sigma + mu;
551 MFloat r[6], s[6], kAbs, energy;
552 std::complex<MFloat> uHat, vHat, wHat;
553 std::complex<MFloat>* fourierCoefficient;
555 kAbs = sqrt(k[0] * k[0] + k[1] * k[1] + k[2] * k[2]);
558 if(
approx(kAbs, 0.0, MFloatEps)) {
559 fourierCoefficient =
new std::complex<MFloat>[3];
561 fourierCoefficient[0] = std::complex<MFloat>(0, 0);
562 fourierCoefficient[1] = std::complex<MFloat>(0, 0);
563 fourierCoefficient[2] = std::complex<MFloat>(0, 0);
566 return fourierCoefficient;
571 energy = pow(kAbs / k0, 4.0) * exp(-2.0 * (kAbs / k0) * (kAbs / k0));
572 energy *= exp(2.0) * 0.499 * (Ma * LBCS)
580 for(
MInt i = 0; i < 6; i++) {
581 r[i] =
randnormal(0.0, PI * sqrt(energy) / (SQRT2 * kAbs));
583 s[i] =
randnormal(0.0, PI * sqrt(energy) / (SQRT2 * kAbs));
587 uHat = (1.0 - k[0] * k[0] / (kAbs * kAbs)) * std::complex<MFloat>(r[0] + r[3], s[0] - s[3])
588 - k[0] * k[1] / (kAbs * kAbs) * std::complex<MFloat>(r[1] + r[4], s[1] - s[4])
589 - k[0] * k[2] / (kAbs * kAbs) * std::complex<MFloat>(r[2] + r[5], s[2] - s[5]);
592 vHat = -k[1] * k[0] / (kAbs * kAbs) * std::complex<MFloat>(r[0] + r[3], s[0] - s[3])
593 + (1.0 - k[1] * k[1] / (kAbs * kAbs)) * std::complex<MFloat>(r[1] + r[4], s[1] - s[4])
594 - k[1] * k[2] / (kAbs * kAbs) * std::complex<MFloat>(r[2] + r[5], s[2] - s[5]);
597 wHat = -k[2] * k[0] / (kAbs * kAbs) * std::complex<MFloat>(r[0] + r[3], s[0] - s[3])
598 - k[2] * k[1] / (kAbs * kAbs) * std::complex<MFloat>(r[1] + r[4], s[1] - s[4])
599 + (1.0 - k[2] * k[2] / (kAbs * kAbs)) * std::complex<MFloat>(r[2] + r[5], s[2] - s[5]);
601 fourierCoefficient =
new std::complex<MFloat>[3];
607 fourierCoefficient[0] = uHat;
608 fourierCoefficient[1] = vHat;
609 fourierCoefficient[2] = wHat;
610 return fourierCoefficient;
621 static std::mt19937 randNumGen;
622 static std::uniform_real_distribution<> distrib{0.0, 1.0};
624 MFloat r[3], kAbs, energy;
625 std::complex<MFloat> uHat, vHat, wHat;
626 std::complex<MFloat>* fourierCoefficient;
628 kAbs = sqrt(k[0] * k[0] + k[1] * k[1] + k[2] * k[2]);
631 if(
approx(kAbs, 0.0, MFloatEps)) {
632 fourierCoefficient =
new std::complex<MFloat>[3];
634 fourierCoefficient[0] = std::complex<MFloat>(0, 0);
635 fourierCoefficient[1] = std::complex<MFloat>(0, 0);
636 fourierCoefficient[2] = std::complex<MFloat>(0, 0);
639 return fourierCoefficient;
645 energy = (kAbs / k0) * (kAbs / k0) * (kAbs / k0) * (kAbs / k0) * exp(-2.0 * (kAbs / k0) * (kAbs / k0));
648 for(
MInt i = 0; i < 3; i++) {
649 r[i] = 2.0 * PI * distrib(randNumGen);
652 uHat = std::complex<MFloat>(cos(r[0]) * energy, sin(r[0]) * energy);
653 vHat = std::complex<MFloat>(cos(r[1]) * energy, sin(r[1]) * energy);
654 wHat = std::complex<MFloat>(cos(r[2]) * energy, sin(r[2]) * energy);
656 fourierCoefficient =
new std::complex<MFloat>[3];
658 fourierCoefficient[0] = uHat;
659 fourierCoefficient[1] = vHat;
660 fourierCoefficient[2] = wHat;
663 return fourierCoefficient;
697 std::complex<MFloat>* fourierCoefficient;
699 fftw_complex *uHatField, *vHatField, *wHatField;
700 fftw_complex *uPhysField, *vPhysField, *wPhysField;
702 fftw_plan planU, planV, planW;
704 MInt xRatio = lx / lxCoarse;
705 MInt yRatio = ly / lyCoarse;
706 MInt zRatio = lz / lzCoarse;
708 if(lx % 2 != 0 || ly % 2 != 0 || lz % 2 != 0) {
709 mTerm(1, AT_,
" FFTInit: domainsize must NOT be an odd number! ");
712 m_log <<
" --- initializing FFTW --- " << std::endl;
713 m_log <<
" domain size = " << lx <<
"x" << ly <<
"x" << lz << std::endl;
716 uPhysField = (fftw_complex*)fftw_malloc(lx * ly * lz *
sizeof(fftw_complex));
717 vPhysField = (fftw_complex*)fftw_malloc(lx * ly * lz *
sizeof(fftw_complex));
718 wPhysField = (fftw_complex*)fftw_malloc(lx * ly * lz *
sizeof(fftw_complex));
721 uHatField = (fftw_complex*)fftw_malloc(lx * ly * lz *
sizeof(fftw_complex));
722 vHatField = (fftw_complex*)fftw_malloc(lx * ly * lz *
sizeof(fftw_complex));
723 wHatField = (fftw_complex*)fftw_malloc(lx * ly * lz *
sizeof(fftw_complex));
726 planU = fftw_plan_dft_3d(lx, ly, lz, uHatField, uPhysField, FFTW_BACKWARD, FFTW_MEASURE);
727 planV = fftw_plan_dft_3d(lx, ly, lz, vHatField, vPhysField, FFTW_BACKWARD, FFTW_MEASURE);
728 planW = fftw_plan_dft_3d(lx, ly, lz, wHatField, wPhysField, FFTW_BACKWARD, FFTW_MEASURE);
731 for(
MInt p = 0; p < lx; p++) {
732 for(
MInt q = 0; q < ly; q++) {
733 for(
MInt r = 0; r < lz; r++) {
734 uHatField[r + lz * (q + ly * p)][0] = 0.0;
735 uHatField[r + lz * (q + ly * p)][1] = 0.0;
736 uPhysField[r + lz * (q + ly * p)][0] = 0.0;
737 uPhysField[r + lz * (q + ly * p)][1] = 0.0;
739 vHatField[r + lz * (q + ly * p)][0] = 0.0;
740 vHatField[r + lz * (q + ly * p)][1] = 0.0;
741 vPhysField[r + lz * (q + ly * p)][0] = 0.0;
742 vPhysField[r + lz * (q + ly * p)][1] = 0.0;
744 wHatField[r + lz * (q + ly * p)][0] = 0.0;
745 wHatField[r + lz * (q + ly * p)][1] = 0.0;
746 wPhysField[r + lz * (q + ly * p)][0] = 0.0;
747 wPhysField[r + lz * (q + ly * p)][1] = 0.0;
761 k0 = 2.0 * PI / (lx / noPeakModes);
763 for(
MInt p = 0; p <= lx / 2; p++) {
764 for(
MInt q = 0; q <= ly / 2; q++) {
765 for(
MInt r = 0; r <= lz / 2; r++) {
767 waveVector[0] = (p)*2.0 * PI / lx;
768 waveVector[1] = (q)*2.0 * PI / ly;
769 waveVector[2] = (r)*2.0 * PI / lz;
774 uHatField[r + lz * (q + ly * p)][0] = std::real(fourierCoefficient[0]);
775 uHatField[r + lz * (q + ly * p)][1] = std::imag(fourierCoefficient[0]);
777 vHatField[r + lz * (q + ly * p)][0] = std::real(fourierCoefficient[1]);
778 vHatField[r + lz * (q + ly * p)][1] = std::imag(fourierCoefficient[1]);
780 wHatField[r + lz * (q + ly * p)][0] = std::real(fourierCoefficient[2]);
781 wHatField[r + lz * (q + ly * p)][1] = std::imag(fourierCoefficient[2]);
784 if(p > 1 && q > 1 && r > 1) {
785 if(p < lx / 2 && q < ly / 2 && r < lz / 2) {
788 uHatField[(lz - r) + lz * ((ly - q) + ly * (lx - p))][0] = uHatField[r + lz * (q + ly * p)][0];
789 uHatField[(lz - r) + lz * ((ly - q) + ly * (lx - p))][1] = -uHatField[r + lz * (q + ly * p)][1];
791 vHatField[(lz - r) + lz * ((ly - q) + ly * (lx - p))][0] = vHatField[r + lz * (q + ly * p)][0];
792 vHatField[(lz - r) + lz * ((ly - q) + ly * (lx - p))][1] = -vHatField[r + lz * (q + ly * p)][1];
794 wHatField[(lz - r) + lz * ((ly - q) + ly * (lx - p))][0] = wHatField[r + lz * (q + ly * p)][0];
795 wHatField[(lz - r) + lz * ((ly - q) + ly * (lx - p))][1] = -wHatField[r + lz * (q + ly * p)][1];
810 for(
MInt p = 0; p < lx; p++) {
811 for(
MInt q = 0; q < ly; q++) {
812 for(
MInt r = 0; r < lz; r++) {
813 uPhysField[r + lz * (q + ly * p)][0] /= sqrt(
MFloat(lx * ly * lz));
814 vPhysField[r + lz * (q + ly * p)][0] /= sqrt(
MFloat(lx * ly * lz));
815 wPhysField[r + lz * (q + ly * p)][0] /= sqrt(
MFloat(lx * ly * lz));
817 uPhysField[r + lz * (q + ly * p)][1] /= sqrt(
MFloat(lx * ly * lz));
818 vPhysField[r + lz * (q + ly * p)][1] /= sqrt(
MFloat(lx * ly * lz));
819 wPhysField[r + lz * (q + ly * p)][1] /= sqrt(
MFloat(lx * ly * lz));
830 for(
MInt p = 0; p < lxCoarse; p++) {
831 for(
MInt q = 0; q < lyCoarse; q++) {
832 for(
MInt r = 0; r < lzCoarse; r++) {
833 uPhysFieldCoarse[r + lzCoarse * (q + lyCoarse * p)] = F0;
834 vPhysFieldCoarse[r + lzCoarse * (q + lyCoarse * p)] = F0;
835 wPhysFieldCoarse[r + lzCoarse * (q + lyCoarse * p)] = F0;
841 for(
MInt p = 0; p < lxCoarse; p++) {
842 for(
MInt q = 0; q < lyCoarse; q++) {
843 for(
MInt r = 0; r < lzCoarse; r++) {
844 for(
MInt i = p * xRatio; i < p * zRatio + xRatio; i++) {
845 for(
MInt j = q * yRatio; j < q * zRatio + yRatio; j++) {
846 for(
MInt k = r * zRatio; k < r * zRatio + zRatio; k++) {
847 uPhysFieldCoarse[r + lzCoarse * (q + lyCoarse * p)] += uPhysField[k + lz * (j + ly * i)][0];
848 vPhysFieldCoarse[r + lzCoarse * (q + lyCoarse * p)] += vPhysField[k + lz * (j + ly * i)][0];
849 wPhysFieldCoarse[r + lzCoarse * (q + lyCoarse * p)] += wPhysField[k + lz * (j + ly * i)][0];
856 for(
MInt p = 0; p < lxCoarse; p++) {
857 for(
MInt q = 0; q < lyCoarse; q++) {
858 for(
MInt r = 0; r < lzCoarse; r++) {
859 uPhysFieldCoarse[r + lzCoarse * (q + lyCoarse * p)] /= (xRatio * yRatio * zRatio);
860 vPhysFieldCoarse[r + lzCoarse * (q + lyCoarse * p)] /= (xRatio * yRatio * zRatio);
861 wPhysFieldCoarse[r + lzCoarse * (q + lyCoarse * p)] /= (xRatio * yRatio * zRatio);
866 fftw_destroy_plan(planU);
867 fftw_destroy_plan(planV);
868 fftw_destroy_plan(planW);
870 fftw_free(uHatField);
871 fftw_free(vHatField);
872 fftw_free(wHatField);
874 fftw_free(uPhysField);
875 fftw_free(vPhysField);
876 fftw_free(wPhysField);
893 fftw_complex* vPhysField,
894 fftw_complex* wPhysField,
904 std::complex<MFloat>* fourierCoefficient;
906 fftw_complex *uHatField, *vHatField, *wHatField;
908 fftw_plan planU, planV, planW;
910 if(lx % 2 != 0 || ly % 2 != 0 || lz % 2 != 0) {
911 std::stringstream errorMessage;
912 errorMessage <<
" FFTInit: domainsize must NOT be an odd number! " << std::endl;
913 mTerm(1, AT_, errorMessage.str());
916 m_log <<
" --- initializing FFTW --- " << std::endl;
917 m_log <<
" domain size = " << lx <<
"x" << ly <<
"x" << lz << std::endl;
920 uHatField = (fftw_complex*)fftw_malloc(lx * ly * lz *
sizeof(fftw_complex));
921 vHatField = (fftw_complex*)fftw_malloc(lx * ly * lz *
sizeof(fftw_complex));
922 wHatField = (fftw_complex*)fftw_malloc(lx * ly * lz *
sizeof(fftw_complex));
925 planU = fftw_plan_dft_3d(lx, ly, lz, uHatField, uPhysField, FFTW_BACKWARD, FFTW_MEASURE);
926 planV = fftw_plan_dft_3d(lx, ly, lz, vHatField, vPhysField, FFTW_BACKWARD, FFTW_MEASURE);
927 planW = fftw_plan_dft_3d(lx, ly, lz, wHatField, wPhysField, FFTW_BACKWARD, FFTW_MEASURE);
930 for(
MInt p = 0; p < lx; p++) {
931 for(
MInt q = 0; q < ly; q++) {
932 for(
MInt r = 0; r < lz; r++) {
933 uHatField[r + lz * (q + ly * p)][0] = 0.0;
934 uHatField[r + lz * (q + ly * p)][1] = 0.0;
935 uPhysField[r + lz * (q + ly * p)][0] = 0.0;
936 uPhysField[r + lz * (q + ly * p)][1] = 0.0;
938 vHatField[r + lz * (q + ly * p)][0] = 0.0;
939 vHatField[r + lz * (q + ly * p)][1] = 0.0;
940 vPhysField[r + lz * (q + ly * p)][0] = 0.0;
941 vPhysField[r + lz * (q + ly * p)][1] = 0.0;
943 wHatField[r + lz * (q + ly * p)][0] = 0.0;
944 wHatField[r + lz * (q + ly * p)][1] = 0.0;
945 wPhysField[r + lz * (q + ly * p)][0] = 0.0;
946 wPhysField[r + lz * (q + ly * p)][1] = 0.0;
960 k0 = 2.0 * PI / (lx / noPeakModes);
962 for(
MInt p = 0; p <= lx / 2; p++) {
963 for(
MInt q = 0; q <= ly / 2; q++) {
964 for(
MInt r = 0; r <= lz / 2; r++) {
966 waveVector[0] = (p)*2.0 * PI / lx;
967 waveVector[1] = (q)*2.0 * PI / ly;
968 waveVector[2] = (r)*2.0 * PI / lz;
973 uHatField[r + lz * (q + ly * p)][0] = std::real(fourierCoefficient[0]);
974 uHatField[r + lz * (q + ly * p)][1] = std::imag(fourierCoefficient[0]);
976 vHatField[r + lz * (q + ly * p)][0] = std::real(fourierCoefficient[1]);
977 vHatField[r + lz * (q + ly * p)][1] = std::imag(fourierCoefficient[1]);
979 wHatField[r + lz * (q + ly * p)][0] = std::real(fourierCoefficient[2]);
980 wHatField[r + lz * (q + ly * p)][1] = std::imag(fourierCoefficient[2]);
983 if(p > 1 && q > 1 && r > 1) {
984 if(p < lx / 2 && q < ly / 2 && r < lz / 2) {
987 uHatField[(lz - r) + lz * ((ly - q) + ly * (lx - p))][0] = uHatField[r + lz * (q + ly * p)][0];
988 uHatField[(lz - r) + lz * ((ly - q) + ly * (lx - p))][1] = -uHatField[r + lz * (q + ly * p)][1];
990 vHatField[(lz - r) + lz * ((ly - q) + ly * (lx - p))][0] = vHatField[r + lz * (q + ly * p)][0];
991 vHatField[(lz - r) + lz * ((ly - q) + ly * (lx - p))][1] = -vHatField[r + lz * (q + ly * p)][1];
993 wHatField[(lz - r) + lz * ((ly - q) + ly * (lx - p))][0] = wHatField[r + lz * (q + ly * p)][0];
994 wHatField[(lz - r) + lz * ((ly - q) + ly * (lx - p))][1] = -wHatField[r + lz * (q + ly * p)][1];
1009 fftw_execute(planU);
1010 fftw_execute(planV);
1011 fftw_execute(planW);
1014 for(
MInt p = 0; p < lx; p++) {
1015 for(
MInt q = 0; q < ly; q++) {
1016 for(
MInt r = 0; r < lz; r++) {
1017 uPhysField[r + lz * (q + ly * p)][0] /= sqrt(
MFloat(lx * ly * lz));
1018 vPhysField[r + lz * (q + ly * p)][0] /= sqrt(
MFloat(lx * ly * lz));
1019 wPhysField[r + lz * (q + ly * p)][0] /= sqrt(
MFloat(lx * ly * lz));
1021 uPhysField[r + lz * (q + ly * p)][1] /= sqrt(
MFloat(lx * ly * lz));
1022 vPhysField[r + lz * (q + ly * p)][1] /= sqrt(
MFloat(lx * ly * lz));
1023 wPhysField[r + lz * (q + ly * p)][1] /= sqrt(
MFloat(lx * ly * lz));
1028 fftw_destroy_plan(planU);
1029 fftw_destroy_plan(planV);
1030 fftw_destroy_plan(planW);
1031 fftw_free(uHatField);
1032 fftw_free(vHatField);
1033 fftw_free(wHatField);
1053 DEBUG(
"computeEnergySpectrum entry", MAIA_DEBUG_TRACE_IN);
1056 const MInt size = nx * ny * nz;
1058 const ptrdiff_t rank = 3;
1059 if(nx % 2 != 0 || ny % 2 != 0 || nz % 2 != 0) {
1060 std::stringstream errorMessage;
1061 errorMessage <<
" FFTInit: domainsize must NOT be an odd number! " << nx <<
" " << ny <<
" " << nz << std::endl;
1062 mTerm(1, AT_, errorMessage.str());
1064 if(howmany < 3)
mTerm(1, AT_,
"expecting at least 3D velocity field");
1066 m_log <<
" --- initializing FFTW --- " << std::endl;
1067 m_log <<
" domain size = " << nx <<
"x" << ny <<
"x" << nz <<
" (" << howmany <<
")" << std::endl;
1072 MPI_Comm_rank(comm, &domainId);
1073 MPI_Comm_size(comm, &noDomains);
1074 MPI_Comm MPI_COMM_FFTW;
1076 maxRank =
mMin(nz, noDomains);
1077 while(nz % maxRank != 0) {
1080 MInt color = (domainId < maxRank) ? 0 : MPI_UNDEFINED;
1081 MPI_Comm_split(comm, color, domainId, &MPI_COMM_FFTW, AT_,
"MPI_COMM_FFTW");
1082 m_log <<
"no ranks for fft: " << maxRank << std::endl;
1085 for(
MInt i = 0; i < locSize; i++) {
1086 urms0 +=
POW2(velocity(i, 0)) +
POW2(velocity(i, 1)) +
POW2(velocity(i, 2));
1088 MPI_Allreduce(MPI_IN_PLACE, &urms0, 1, MPI_DOUBLE, MPI_SUM, comm, AT_,
"MPI_IN_PLACE",
"urms0");
1089 urms0 = sqrt(F1B3 * urms0 / fsize);
1091 MInt fftLocSize = 0;
1092 ptrdiff_t alloc_local = 0, local_n0 = 0, local_0_start = 0;
1093 fftw_complex* hatField =
nullptr;
1096 const MFloat time0 = MPI_Wtime();
1098 const ptrdiff_t n[3] = {nx, ny, nz};
1100 alloc_local = (domainId < maxRank) ? fftw_mpi_local_size_many(rank, n, howmany, FFTW_MPI_DEFAULT_BLOCK, MPI_COMM_FFTW,
1101 &local_n0, &local_0_start)
1106 if(domainId < maxRank) {
1107 hatField = &hatFieldMem[0];
1119 MLong locOffset = (domainId < maxRank) ? ((
MInt)local_0_start) * ny * nz : size;
1121 MPI_Allgather(&locOffset, 1, MPI_LONG, &offsets[0], 1, MPI_LONG, comm, AT_,
"locOffset",
"offsets[0]");
1122 offsets(noDomains) = size;
1123 if(domainId < maxRank) {
1124 if(offsets(domainId) != locOffset || offsets(domainId + 1) != ((
MInt)(local_0_start + local_n0)) * ny * nz)
1125 mTerm(1, AT_,
"wrong size 0");
1127 for(
MInt i = 0; i < locSize; i++) {
1128 MInt j = indices(i);
1129 MInt nghbrDomain =
mMin(maxRank - 1, j / (size / maxRank));
1130 while(j < offsets(nghbrDomain) || j >= offsets(nghbrDomain + 1)) {
1131 if(j < offsets(nghbrDomain)) nghbrDomain--;
1132 if(j >= offsets(nghbrDomain + 1)) nghbrDomain++;
1134 if(nghbrDomain >= maxRank)
mTerm(1, AT_,
"wrong domain");
1135 noSend(nghbrDomain)++;
1137 MPI_Alltoall(&noSend[0], 1, MPI_INT, &noRecv[0], 1, MPI_INT, comm, AT_,
"noSend[0]",
"noRecv[0]");
1142 for(
MInt i = 0; i < noDomains; i++) {
1143 recvOffsets(i) = recvSize;
1144 sendOffsets(i) = sendSize;
1145 sendSize += noSend(i);
1146 recvSize += noRecv(i);
1148 recvOffsets(noDomains) = recvSize;
1149 sendOffsets(noDomains) = sendSize;
1155 for(
MInt i = 0; i < locSize; i++) {
1156 MInt j = indices(i);
1157 MInt nghbrDomain =
mMin(maxRank - 1, j / (size / maxRank));
1158 while(j < offsets(nghbrDomain) || j >= offsets(nghbrDomain + 1)) {
1159 if(j < offsets(nghbrDomain)) nghbrDomain--;
1160 if(j >= offsets(nghbrDomain + 1)) nghbrDomain++;
1162 if(nghbrDomain >= maxRank)
mTerm(1, AT_,
"wrong domain");
1163 if(sendOffsets(nghbrDomain) + noSend(nghbrDomain) >= sendOffsets(nghbrDomain + 1))
mTerm(1, AT_,
"wrong size");
1164 for(
MInt k = 0; k < howmany; k++) {
1165 sendData(sendOffsets(nghbrDomain) + noSend(nghbrDomain), k) = velocity(i, k);
1167 sendIndices(sendOffsets(nghbrDomain) + noSend(nghbrDomain)) = j;
1168 if(j < offsets(nghbrDomain) || j >= offsets(nghbrDomain + 1))
mTerm(1, AT_,
"wrong size 01");
1169 noSend(nghbrDomain)++;
1171 for(
MInt i = 0; i < noDomains; i++) {
1172 if(noSend(i) != sendOffsets(i + 1) - sendOffsets(i))
mTerm(1, AT_,
"wrong size 1");
1173 if(noRecv(i) != recvOffsets(i + 1) - recvOffsets(i))
mTerm(1, AT_,
"wrong size 1");
1177 sendReq.
fill(MPI_REQUEST_NULL);
1179 for(
MInt i = 0; i < noDomains; i++) {
1180 if(noSend(i) == 0)
continue;
1181 MPI_Issend(&sendData[howmany * sendOffsets(i)], howmany * noSend(i), MPI_DOUBLE, i, 123, comm, &sendReq[cnt], AT_,
1182 "sendData[howmany * sendOffsets(i)]");
1185 for(
MInt i = 0; i < noDomains; i++) {
1186 if(noRecv(i) == 0)
continue;
1187 MPI_Recv(&recvData[howmany * recvOffsets(i)], howmany * noRecv(i), MPI_DOUBLE, i, 123, comm, MPI_STATUS_IGNORE, AT_,
1188 "recvData[howmany * recvOffsets(i)]");
1190 if(cnt > 0)
MPI_Waitall(cnt, &sendReq[0], MPI_STATUSES_IGNORE, AT_);
1191 sendReq.
fill(MPI_REQUEST_NULL);
1193 for(
MInt i = 0; i < noDomains; i++) {
1194 if(noSend(i) == 0)
continue;
1195 MPI_Issend(&sendIndices[sendOffsets(i)], noSend(i), MPI_INT, i, 124, comm, &sendReq[cnt], AT_,
1196 "sendIndices[sendOffsets(i)]");
1199 for(
MInt i = 0; i < noDomains; i++) {
1200 if(noRecv(i) == 0)
continue;
1201 MPI_Recv(&recvIndices[recvOffsets(i)], noRecv(i), MPI_INT, i, 124, comm, MPI_STATUS_IGNORE, AT_,
1202 "recvIndices[recvOffsets(i)]");
1204 if(cnt > 0)
MPI_Waitall(cnt, &sendReq[0], MPI_STATUSES_IGNORE, AT_);
1206 if(domainId < maxRank) {
1207 for(
MInt i = 0; i < recvSize; i++) {
1208 MInt j = recvIndices(i);
1209 if(j < ((
MInt)local_0_start) * ny * nz || j >= ((
MInt)(local_0_start + local_n0)) * ny * nz)
1210 mTerm(1, AT_,
"wrong size 2");
1211 MInt pos = j - (((
MInt)local_0_start) * ny * nz);
1212 for(
MInt k = 0; k < howmany; k++) {
1213 hatField[howmany * pos + k][0] = recvData(i, k);
1214 hatField[howmany * pos + k][1] = F0;
1217 fftLocSize = recvSize;
1220 for(
MInt i = 0; i < fftLocSize; i++) {
1221 for(
MInt k = 0; k < 3; k++) {
1222 couplcheck -= hatField[howmany * i + k][0] * hatField[howmany * i + 3 + k][0];
1225 MPI_Allreduce(MPI_IN_PLACE, &couplcheck, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_FFTW, AT_,
"MPI_IN_PLACE",
"couplcheck");
1227 std::cerr <<
"couplecheck fft " << couplcheck <<
" " << couplcheck *
POW3(0.25 / 64.0) << std::endl;
1231 if(domainId < maxRank) {
1233 plan = fftw_mpi_plan_many_dft(rank, n, howmany, FFTW_MPI_DEFAULT_BLOCK, FFTW_MPI_DEFAULT_BLOCK, hatField, hatField,
1234 MPI_COMM_FFTW, FFTW_FORWARD, FFTW_ESTIMATE);
1236 fftw_destroy_plan(plan);
1238 for(
MInt i = 0; i < fftLocSize; i++) {
1239 for(
MInt j = 0; j < howmany; j++) {
1240 hatField[howmany * i + j][0] /= fsize;
1241 hatField[howmany * i + j][1] /= fsize;
1246 const MFloat time1 = MPI_Wtime();
1248 m_log <<
"parallel fftw time " << time1 - time0 << std::endl;
1258 static const MInt referenceCubeSize =
1259 ((
Context::propertyExists(
"referenceCubeSize")) ? Context::getBasicProperty<MInt>(
"referenceCubeSize", AT_) : 1);
1265 const MFloat k0 = F2 * PI / referenceCubeSize;
1270 if(kMinSpec > 0 && kMaxSpec > 0) {
1272 kMin =
static_cast<float>(kMinSpec) * k0;
1273 kMax =
static_cast<float>(kMaxSpec) * k0;
1274 deltaK = (kMax - kMin) / ((
MFloat)(kMaxSpec - 1));
1276 noBins =
mMax(nx,
mMax(ny, nz)) / 2;
1279 deltaK = (kMax - kMin) / ((
MFloat)(noBins - 1));
1294 spectrumBnd[0] = kMin - F1B2 * deltaK;
1295 const MFloat spectrumBnd00 = kMin - F3B4 * deltaK;
1296 for(
MInt i = 0; i < noBins; i++) {
1297 spectrumBnd[i + 1] = spectrumBnd[i] + deltaK;
1306 spectrumSum.
fill(F0);
1307 spectrumSum2.
fill(F0);
1310 static const MBool computeTransferRate =
1311 ((
Context::propertyExists(
"computeTransferRate")) ? Context::getBasicProperty<MBool>(
"computeTransferRate", AT_)
1313 if(computeTransferRate) {
1316 MPI_Allgather(&fftLocSize, 1, MPI_INT, &noDatPerDomain[0], 1, MPI_INT, comm, AT_,
"fftLocSize",
1317 "noDatPerDomain[0]");
1318 dataOffsets.
fill(0);
1319 for(
MInt d = 0; d < noDomains; d++) {
1320 dataOffsets(d + 1) = dataOffsets(d) + noDatPerDomain(d);
1323 MPI_Request sendReqLoc = MPI_REQUEST_NULL;
1324 fftw_complex* uHatGlobal = fftw_alloc_complex(3 * size);
1325 fftw_complex* uHatGlobalTmp =
nullptr;
1326 for(
MInt i = 0; i < fftLocSize; i++) {
1327 for(
MInt j = 0; j < 3; j++) {
1328 uHatGlobal[3 * i + j][0] = hatField[howmany * i + j][0];
1329 uHatGlobal[3 * i + j][1] = hatField[howmany * i + j][1];
1332 if(fftLocSize > 0) {
1333 MPI_Issend(&uHatGlobal[0], 6 * fftLocSize, MPI_DOUBLE, 0, 18, comm, &sendReqLoc, AT_,
"uHatGlobal[0]");
1336 uHatGlobalTmp = fftw_alloc_complex(3 * size);
1337 for(
MInt d = 0; d < noDomains; d++) {
1338 if(noDatPerDomain[d] > 0) {
1339 MPI_Recv(&(uHatGlobalTmp[3 * dataOffsets[d]][0]), 6 * noDatPerDomain[d], MPI_DOUBLE, d, 18, comm,
1340 MPI_STATUSES_IGNORE, AT_,
"(uHatGlobalTmp[3 * dataOffsets[d]][0])");
1344 if(fftLocSize > 0) {
1345 MPI_Wait(&sendReqLoc, MPI_STATUSES_IGNORE, AT_);
1350 for(
MInt i0 = 0; i0 < nx; i0++) {
1351 for(
MInt i1 = 0; i1 < ny; i1++) {
1352 for(
MInt i2 = 0; i2 < nz; i2++) {
1353 MInt j0 = (i0 > nx / 2) ? i0 - nx : i0;
1354 MInt j1 = (i1 > ny / 2) ? i1 - ny : i1;
1355 MInt j2 = (i2 > nz / 2) ? i2 - nz : i2;
1361 for(
MInt j = 0; j < 3; j++) {
1362 uHatGlobal[3 * pos1 + j][0] = uHatGlobalTmp[3 * pos0 + j][0];
1363 uHatGlobal[3 * pos1 + j][1] = uHatGlobalTmp[3 * pos0 + j][1];
1368 fftw_free(uHatGlobalTmp);
1371 MPI_Bcast(&uHatGlobal[0], 6 * size, MPI_DOUBLE, 0, comm, AT_,
"uHatGlobal");
1379 MInt noWaveNumbers = 0;
1380 MLong weightSum = 0;
1381 for(
MInt pos = 0; pos < size; pos++) {
1383 MInt i1 = (pos / nz) % ny;
1384 MInt i0 = pos / (ny * nz);
1385 if(pos != i2 + nz * (i1 + ny * (i0)))
mTerm(1, AT_,
"index mismatch");
1387 MInt j0 = i0 - nx / 2 + 1;
1388 MInt j1 = i1 - ny / 2 + 1;
1389 MInt j2 = i2 - nz / 2 + 1;
1390 k[0] = ((
MFloat)j0) * k0;
1391 k[1] = ((
MFloat)j1) * k0;
1392 k[2] = ((
MFloat)j2) * k0;
1394 MFloat kAbs = sqrt(k[0] * k[0] + k[1] * k[1] + k[2] * k[2]);
1395 if(kAbs > spectrumBnd[noBins] + 1e-12)
continue;
1396 if(kAbs < spectrumBnd[0] - 1e-12)
continue;
1398 MInt p0Min = std::max(0, i0 - nx / 2);
1399 MInt p0Max = std::min(nx, i0 + nx / 2);
1400 MInt p1Min = std::max(0, i1 - ny / 2);
1401 MInt p1Max = std::min(ny, i1 + ny / 2);
1402 MInt p2Min = std::max(0, i2 - nz / 2);
1403 MInt p2Max = std::min(nz, i2 + nz / 2);
1404 MLong weight = ((p0Max - p0Min) * (p1Max - p1Min) * (p2Max - p2Min));
1406 weightSum += weight;
1412 MLong domainSize = weightSum / noDomainsLong;
1417 for(
MInt pos = 0; pos < size; pos++) {
1419 MInt i1 = (pos / nz) % ny;
1420 MInt i0 = pos / (ny * nz);
1421 if(pos != i2 + nz * (i1 + ny * (i0)))
mTerm(1, AT_,
"index mismatch");
1423 MInt j0 = i0 - nx / 2 + 1;
1424 MInt j1 = i1 - ny / 2 + 1;
1425 MInt j2 = i2 - nz / 2 + 1;
1426 k[0] = ((
MFloat)j0) * k0;
1427 k[1] = ((
MFloat)j1) * k0;
1428 k[2] = ((
MFloat)j2) * k0;
1430 MFloat kAbs = sqrt(k[0] * k[0] + k[1] * k[1] + k[2] * k[2]);
1431 if(kAbs > spectrumBnd[noBins] + 1e-12)
continue;
1432 if(kAbs < spectrumBnd[0] - 1e-12)
continue;
1434 MInt p0Min = std::max(0, i0 - nx / 2);
1435 MInt p0Max = std::min(nx, i0 + nx / 2);
1436 MInt p1Min = std::max(0, i1 - ny / 2);
1437 MInt p1Max = std::min(ny, i1 + ny / 2);
1438 MInt p2Min = std::max(0, i2 - nz / 2);
1439 MInt p2Max = std::min(nz, i2 + nz / 2);
1440 MLong weight = ((p0Max - p0Min) * (p1Max - p1Min) * (p2Max - p2Min));
1442 if(weightSum <= (domainSize * domainIdLong) && (weightSum + weight) > (domainSize * domainIdLong)) posMin = pos;
1443 if(weightSum <= (domainSize * (domainIdLong + 1)) && (weightSum + weight) > (domainSize * (domainIdLong + 1)))
1446 weightSum += weight;
1451 for(
MInt pos = posMin; pos < posMax; pos++) {
1452 const MInt i2 = pos % nz;
1453 const MInt i1 = (pos / nz) % ny;
1454 const MInt i0 = pos / (ny * nz);
1456 const MInt j0 = i0 - nx / 2 + 1;
1457 const MInt j1 = i1 - ny / 2 + 1;
1458 const MInt j2 = i2 - nz / 2 + 1;
1460 const MFloat kAbs2 =
mMax(1e-12, k[0] * k[0] + k[1] * k[1] + k[2] * k[2]);
1461 const MFloat kAbs =
mMax(1e-12, sqrt(k[0] * k[0] + k[1] * k[1] + k[2] * k[2]));
1463 if(kAbs > spectrumBnd[noBins] + 1e-12)
continue;
1464 const MInt bin = ((
MInt)((kAbs - spectrumBnd[0] + 1e-12) / deltaK));
1465 const MInt bin2 = ((
MInt)((kAbs - spectrumBnd00 + 1e-12) / deltaK));
1467 const MFloat kjl[3][3] = {
1468 {1.0 - (k[0] * k[0] / kAbs2), 0.0 - (k[0] * k[1] / kAbs2), 0.0 - (k[0] * k[2] / kAbs2)},
1469 {0.0 - (k[1] * k[0] / kAbs2), 1.0 - (k[1] * k[1] / kAbs2), 0.0 - (k[1] * k[2] / kAbs2)},
1470 {0.0 - (k[2] * k[0] / kAbs2), 0.0 - (k[2] * k[1] / kAbs2), 1.0 - (k[2] * k[2] / kAbs2)}};
1472 const MInt p0Min = std::max(0, i0 - nx / 2);
1473 const MInt p0Max = std::min(nx, i0 + nx / 2);
1474 const MInt p1Min = std::max(0, i1 - ny / 2);
1475 const MInt p1Max = std::min(ny, i1 + ny / 2);
1476 const MInt p2Min = std::max(0, i2 - nz / 2);
1477 const MInt p2Max = std::min(nz, i2 + nz / 2);
1481 for(
MInt p0 = p0Min; p0 < p0Max; p0++) {
1482 for(
MInt p1 = p1Min; p1 < p1Max; p1++) {
1483 for(
MInt p2 = p2Min; p2 < p2Max; p2++) {
1484 const MInt pos1 = p2 + nz * (p1 + ny * (p0));
1485 const MInt s0 = i0 - p0 + nx / 2 - 1;
1486 const MInt s1 = i1 - p1 + ny / 2 - 1;
1487 const MInt s2 = i2 - p2 + nz / 2 - 1;
1488 const MInt pos2 = s2 + nz * (s1 + ny * (s0));
1490 for(
MInt i = 0; i < 3; i++) {
1491 for(
MInt j = 0; j < 3; j++) {
1492 for(
MInt l = 0; l < 3; l++) {
1493 trans += k[i] * kjl[j][l]
1494 *
triadImag(uHatGlobal[3 * pos1 + l], uHatGlobal[3 * pos2 + i], uHatGlobal[3 * pos + j]);
1502 if(bin > -1 && bin < noBins) transfer(bin) += trans;
1503 if(bin2 > -1 && bin2 < noBins) transfer2(bin2) += trans;
1506 MPI_Allreduce(MPI_IN_PLACE, &transfer[0], noBins, MPI_DOUBLE, MPI_SUM, comm, AT_,
"MPI_IN_PLACE",
"transfer[0]");
1507 MPI_Allreduce(MPI_IN_PLACE, &transfer2[0], noBins, MPI_DOUBLE, MPI_SUM, comm, AT_,
"MPI_IN_PLACE",
"transfer2[0]");
1508 fftw_free(uHatGlobal);
1511 const MFloat time2 = MPI_Wtime();
1513 if(domainId < maxRank) {
1514 for(
MInt i0 = (
MInt)local_0_start; i0 < (
MInt)(local_0_start + local_n0); i0++) {
1515 for(
MInt i1 = 0; i1 < ny; i1++) {
1516 for(
MInt i2 = 0; i2 < nz; i2++) {
1518 MInt j0 = (i0 > nx / 2) ? i0 - nx : i0;
1519 MInt j1 = (i1 > ny / 2) ? i1 - ny : i1;
1520 MInt j2 = (i2 > nz / 2) ? i2 - nz : i2;
1521 k[0] = ((
MFloat)j0) * k0;
1522 k[1] = ((
MFloat)j1) * k0;
1523 k[2] = ((
MFloat)j2) * k0;
1525 MInt pos = i2 + nz * (i1 + ny * (i0 - ((
MInt)local_0_start)));
1526 if(pos < 0 || pos >= fftLocSize)
mTerm(1, AT_,
"wrong size 3");
1528 MFloat kAbs = sqrt(k[0] * k[0] + k[1] * k[1] + k[2] * k[2]);
1532 for(
MInt q = 0; q < 3; q++) {
1533 eng += F1B2 * (
POW2(hatField[howmany * pos + q][0]) +
POW2(hatField[howmany * pos + q][1]));
1539 for(
MInt q = 0; q < 3; q++) {
1540 coupl += (hatField[howmany * pos + q][0] * hatField[howmany * pos + 3 + q][0]
1541 + hatField[howmany * pos + q][1] * hatField[howmany * pos + 3 + q][1]);
1542 dedt += (hatField[howmany * pos + 6 + q][0] * hatField[howmany * pos + q][0]
1543 + hatField[howmany * pos + 6 + q][1] * hatField[howmany * pos + q][1]);
1546 if(kAbs > spectrumBnd[noBins] + 1e-12)
continue;
1548 MInt bin = ((
MInt)((kAbs - spectrumBnd[0] + 1e-12) / deltaK));
1549 MInt bin2 = ((
MInt)((kAbs - spectrumBnd00 + 1e-12) / deltaK));
1550 if(bin > -1 && bin < noBins) {
1551 spectrum(bin) += eng;
1552 coupling(bin) += coupl;
1554 spectrumSum(bin) += F1;
1556 if(bin2 > -1 && bin2 < noBins) {
1557 spectrumSum2(bin2) += F1;
1563 MPI_Allreduce(MPI_IN_PLACE, &spectrum[0], noBins, MPI_DOUBLE, MPI_SUM, MPI_COMM_FFTW, AT_,
"MPI_IN_PLACE",
1565 MPI_Allreduce(MPI_IN_PLACE, &coupling[0], noBins, MPI_DOUBLE, MPI_SUM, MPI_COMM_FFTW, AT_,
"MPI_IN_PLACE",
1567 MPI_Allreduce(MPI_IN_PLACE, &rate[0], noBins, MPI_DOUBLE, MPI_SUM, MPI_COMM_FFTW, AT_,
"MPI_IN_PLACE",
"rate[0]");
1568 MPI_Allreduce(MPI_IN_PLACE, &spectrumSum[0], noBins, MPI_DOUBLE, MPI_SUM, MPI_COMM_FFTW, AT_,
"MPI_IN_PLACE",
1570 MPI_Allreduce(MPI_IN_PLACE, &spectrumSum2[0], noBins, MPI_DOUBLE, MPI_SUM, MPI_COMM_FFTW, AT_,
"MPI_IN_PLACE",
1573 for(
MInt i = 0; i < noBins; i++) {
1574 MFloat db = spectrumBnd00 - spectrumBnd[0];
1576 F4B3 * PI * (
POW3(spectrumBnd[i + 1]) -
POW3(spectrumBnd[i])) / (spectrumBnd[i + 1] - spectrumBnd[i]);
1577 MFloat vol2 = F4B3 * PI * (
POW3(spectrumBnd[i + 1] + db) -
POW3(spectrumBnd[i] + db))
1578 / (spectrumBnd[i + 1] - spectrumBnd[i]);
1579 spectrum(i) *= vol / (spectrumSum(i) *
POW3(k0));
1580 coupling(i) *= vol / (spectrumSum(i) *
POW3(k0));
1581 transfer(i) *= vol / (spectrumSum(i) *
POW3(k0));
1582 transfer2(i) *= vol2 / (spectrumSum2(i) *
POW3(k0));
1583 rate(i) *= vol / (spectrumSum(i) *
POW3(k0));
1586 for(
MInt i = 0; i < noBins; i++) {
1589 for(
MInt j = 0; j < i; j++) {
1590 flux(i, 0) += transfer(j) * (spectrumBnd[j + 1] - spectrumBnd[j]) / k0;
1592 for(
MInt j = i; j < noBins; j++) {
1593 flux(i, 1) += transfer(j) * (spectrumBnd[j + 1] - spectrumBnd[j]) / k0;
1597 for(
MInt j = 0; j < i; j++) {
1598 flux2(i, 0) += transfer2(j) * (spectrumBnd[j + 1] - spectrumBnd[j]) / k0;
1600 for(
MInt j = i; j < noBins; j++) {
1601 flux2(i, 1) += transfer2(j) * (spectrumBnd[j + 1] - spectrumBnd[j]) / k0;
1608 ofl.open(
"./out/energySpectrum_00" + std::to_string(
globalTimeStep), std::ios_base::out | std::ios_base::trunc);
1609 ofl2.open(
"./out/energySpectrum_coarse_00" + std::to_string(
globalTimeStep),
1610 std::ios_base::out | std::ios_base::trunc);
1611 if(ofl.is_open() && ofl.good() && ofl2.is_open() && ofl2.good()) {
1620 for(
MInt i = 0; i < noBins; i++) {
1621 urms += spectrum(i) * (spectrumBnd[i + 1] - spectrumBnd[i]);
1623 urms = sqrt(F2B3 * urms);
1624 for(
MInt i = 0; i < noBins; i++) {
1625 MFloat k = F1B2 * (spectrumBnd[i + 1] + spectrumBnd[i]);
1627 if(std::isnan(Ek) || std::isnan(coupling(i)) || std::isnan(rate(i)))
continue;
1628 energy += (spectrumBnd[i + 1] - spectrumBnd[i]) * Ek;
1629 dissip += F2 * viscosity *
POW2(k) * (spectrumBnd[i + 1] - spectrumBnd[i]) * Ek;
1630 length += (F1B2 * PI /
POW2(urms)) * (spectrumBnd[i + 1] - spectrumBnd[i]) * Ek / (k);
1631 force += (spectrumBnd[i + 1] - spectrumBnd[i]) * coupling(i);
1632 dedt += (spectrumBnd[i + 1] - spectrumBnd[i]) * rate(i);
1633 transf += (spectrumBnd[i + 1] - spectrumBnd[i]) * transfer(i);
1634 transf2 += (spectrumBnd[i + 1] - spectrumBnd[i]) * transfer2(i);
1636 ofl <<
"# Energy spectrum at time step " <<
globalTimeStep <<
", total energy Ek=" << energy
1637 <<
", dissipation rate=" << dissip <<
", u_rms=" << urms <<
" (" << urms0
1638 <<
"), integral length scale=" << length <<
", Kolmogorov time scale=" << sqrt(viscosity / dissip)
1639 <<
", coupling=" << force <<
", dedt=" << dedt <<
", transfer=" << transf <<
", transfer2=" << transf2
1641 ofl <<
"# 1: wave number k" << std::endl;
1642 ofl <<
"# 2: energy E(k)" << std::endl;
1643 ofl <<
"# 3: viscous dissipation rate D(k)" << std::endl;
1644 ofl <<
"# 4: transfer rate T(k)" << std::endl;
1645 ofl <<
"# 5: coupling rate Psi(k)" << std::endl;
1646 ofl <<
"# 6: flux -F(k)" << std::endl;
1647 ofl <<
"# 7: flux F(k)" << std::endl;
1648 ofl <<
"# 8: dE/dt(k)" << std::endl;
1649 ofl <<
"# 9: alternative transfer rate T(k)" << std::endl;
1650 ofl <<
"# 10: alternative flux -F(k)" << std::endl;
1651 ofl <<
"# 11: alternative flux F(k)" << std::endl;
1652 ofl <<
"# 12: number of samples in corresponding bin" << std::endl;
1653 ofl <<
"# 13: lower boundary of corresponding bin" << std::endl;
1654 ofl <<
"# 14: upper boundary of corresponding bin" << std::endl;
1655 ofl <<
"# 15: number of samples other spectrum: " << std::endl;
1656 ofl <<
"# 16: 4 * PI * k^2" << std::endl;
1657 ofl <<
"# 17: 4/3 * PI * (upperBndry^3 - lowerBndry^3)" << std::endl;
1658 for(
MInt i = 0; i < noBins; i++) {
1659 MFloat k = F1B2 * (spectrumBnd[i + 1] + spectrumBnd[i]);
1661 MFloat coupl = coupling(i);
1662 MFloat trans = transfer(i);
1663 MFloat trans2 = transfer2(i);
1664 ofl << k / k0 <<
" " << Ek <<
" " << F2 *
POW2(k) * viscosity * Ek <<
" " << trans <<
" " << coupl <<
" "
1665 << flux(i, 0) <<
" " << flux(i, 1) <<
" " << rate(i) <<
" " << trans2 <<
" " << flux2(i, 0) <<
" "
1666 << flux2(i, 1) <<
" " << spectrumSum(i) <<
" " << spectrumBnd[i] <<
" " << spectrumBnd[i + 1] <<
" "
1667 << spectrumSum2(i) <<
" " << F4 * PI *
POW2(k) <<
" "
1668 << F4B3 * PI * (
POW3(spectrumBnd[i + 1]) -
POW3(spectrumBnd[i])) << std::endl;
1670 for(
MInt i = 0; i < noBins / 2; i++) {
1671 const MInt i0 = 2 * i;
1672 const MInt i1 = 2 * i + 1;
1673 const MFloat k = F1B2 * (spectrumBnd[i1 + 1] + spectrumBnd[i0]);
1675 F4B3 * PI * (
POW3(spectrumBnd[i0 + 1]) -
POW3(spectrumBnd[i0])) / (spectrumBnd[i0 + 1] - spectrumBnd[i0]);
1677 F4B3 * PI * (
POW3(spectrumBnd[i1 + 1]) -
POW3(spectrumBnd[i1])) / (spectrumBnd[i1 + 1] - spectrumBnd[i1]);
1679 F4B3 * PI * (
POW3(spectrumBnd[i1 + 1]) -
POW3(spectrumBnd[i0])) / (spectrumBnd[i1 + 1] - spectrumBnd[i0]);
1680 MFloat f0 = spectrumSum(i0) * vol / (vol0 * (spectrumSum(i0) + spectrumSum(i1)));
1681 MFloat f1 = spectrumSum(i1) * vol / (vol1 * (spectrumSum(i0) + spectrumSum(i1)));
1683 ofl2 << k / k0 <<
" " << f1 * spectrum(i1) + f0 * spectrum(i0) <<
" "
1684 << F2 *
POW2(k) * viscosity * (f1 * spectrum(i1) + f0 * spectrum(i0)) <<
" "
1685 << f1 * transfer(i1) + f0 * transfer(i0) <<
" " << f1 * coupling(i1) + f0 * coupling(i0) <<
" "
1686 << f1 * flux(i1, 0) + f0 * flux(i0, 0) <<
" " << f1 * flux(i1, 1) + f0 * flux(i0, 1) <<
" "
1687 << f1 * rate(i1) + f0 * rate(i0) <<
" " << f1 * transfer2(i1) + f0 * transfer2(i0) <<
" "
1688 << f1 * flux2(i1, 0) + f0 * flux2(i0, 0) <<
" " << f1 * flux2(i1, 1) + f0 * flux2(i0, 1) <<
" "
1689 << spectrumSum(i0) + spectrumSum(i1) <<
" " << spectrumBnd[i0] <<
" " << spectrumBnd[i1 + 1] <<
" "
1690 << spectrumSum2(i0) + spectrumSum2(i1) <<
" " << F4 * PI *
POW2(k) <<
" "
1691 << F4B3 * PI * (
POW3(spectrumBnd[i1 + 1]) -
POW3(spectrumBnd[i0])) << std::endl;
1702 const MFloat time3 = MPI_Wtime();
1705 std::cerr <<
"fft time " << time1 - time0 <<
" " << time2 - time1 <<
" " << time3 - time2 << std::endl;
1707 m_log <<
"fft finished" << std::endl;
1709 DEBUG(
"computeEnergySpectrum return", MAIA_DEBUG_TRACE_OUT);
static MBool propertyExists(const MString &name, MInt solver=m_noSolvers)
This function checks if a property exists in general.
This class is a ScratchSpace.
void fill(T val)
fill the scratch with a given value
void mTerm(const MInt errorCode, const MString &location, const MString &message)
constexpr Real POW3(const Real x)
constexpr Real POW2(const Real x)
MBool approx(const T &, const U &, const T)
constexpr T mMin(const T &x, const T &y)
constexpr T mMax(const T &x, const T &y)
int MPI_Recv(void *buf, int count, MPI_Datatype datatype, int source, int tag, MPI_Comm comm, MPI_Status *status, const MString &name, const MString &varname)
same as MPI_Recv
int MPI_Issend(const void *buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm, MPI_Request *request, const MString &name, const MString &varname)
same as MPI_Issend
int MPI_Wait(MPI_Request *request, MPI_Status *status, const MString &name)
same as MPI_Wait
int MPI_Waitall(int count, MPI_Request *request, MPI_Status *status, const MString &name)
same as MPI_Waitall
int MPI_Allreduce(const void *sendbuf, void *recvbuf, int count, MPI_Datatype datatype, MPI_Op op, MPI_Comm comm, const MString &name, const MString &sndvarname, const MString &rcvvarname)
same as MPI_Allreduce
int MPI_Alltoall(const void *sendbuf, int sendcount, MPI_Datatype sendtype, void *recvbuf, int recvcount, MPI_Datatype recvtype, MPI_Comm comm, const MString &name, const MString &sndvarname, const MString &rcvvarname)
same as MPI_Alltoall
int MPI_Comm_split(MPI_Comm comm, int color, int key, MPI_Comm *newcomm, const MString &name, const MString &varname)
same as MPI_Comm_split, but updates the number of MPI communicators
int MPI_Bcast(void *buffer, int count, MPI_Datatype datatype, int root, MPI_Comm comm, const MString &name, const MString &varname)
same as MPI_Bcast
int MPI_Allgather(const void *sendbuf, int sendcount, MPI_Datatype sendtype, void *recvbuf, int recvcount, MPI_Datatype recvtype, MPI_Comm comm, const MString &name, const MString &sndvarname, const MString &rcvvarname)
same as MPI_Allgather
MFloat randnormal(MFloat mu, MFloat sigma)
std::complex< MFloat > * getFourierCoefficient2(MFloat *k, MFloat k0)
MFloat triadImag(fftw_complex &a, fftw_complex &b, fftw_complex &c)
void initFftFilter(MFloat *uPhysFieldCoarse, MFloat *vPhysFieldCoarse, MFloat *wPhysFieldCoarse, MInt lx, MInt ly, MInt lz, MInt lxCoarse, MInt lyCoarse, MInt lzCoarse, MInt noPeakModes, const MFloat Ma)
Generates a velocity field from Fourier-modes using FFTW The disturbances are generated and filtered ...
void initFft(fftw_complex *uPhysField, fftw_complex *vPhysField, fftw_complex *wPhysField, MInt lx, MInt ly, MInt lz, MInt noPeakModes, const MFloat Ma)
Generates a velocity field from Fourier-modes using FFTW.
MInt getGlobalPosFFTW(MInt i0, MInt i1, MInt i2, MInt ny, MInt nz)
std::complex< MFloat > * getFourierCoefficient(MFloat *k, MFloat k0, const MFloat Ma)
void computeEnergySpectrum(MFloatScratchSpace &velocity, MIntScratchSpace &indices, const ptrdiff_t howmany, MInt locSize, MInt nx, MInt ny, MInt nz, MFloat viscosity, const MPI_Comm comm)
Compute energy spectrum on unity cube.
Namespace for auxiliary functions/classes.