MAIA bb96820c
Multiphysics at AIA
Loading...
Searching...
No Matches
lbsolverdxqy.cpp
Go to the documentation of this file.
1// Copyright (C) 2024 The m-AIA AUTHORS
2//
3// This file is part of m-AIA (https://git.rwth-aachen.de/aia/m-AIA/m-AIA)
4//
5// SPDX-License-Identifier: LGPL-3.0-only
6
7#include "lbsolverdxqy.h"
8
9#include <algorithm>
10#include "COMM/mpioverride.h"
11#include "UTIL/maiafftw.h"
12#include "UTIL/parallelfor.h"
13#include "globals.h"
14#include "lbbndcnddxqy.h"
15#include "lbconstants.h"
16#include "lbfunctions.h"
17#include "lbgridboundarycell.h"
18#include "lbinterfacedxqy.h"
19#include "lbsyseqn.h"
20
21using namespace std;
22using namespace lbconstants;
23
24template <MInt nDim, MInt nDist, class SysEqn>
26 Geometry<nDim>& geometry_, const MPI_Comm comm)
27 : LbSolver<nDim>(id, noDistributions, gridProxy_, geometry_, comm),
28 m_srcTermController(this),
29 C1(5.0),
30 C2(-3.05),
31 C3(2.5),
32 C4(5.5) // Constants for Law of the Wall
33{
34 TRACE();
35
36 if(m_isRefined || this->m_adaptation) m_interface = new LbInterfaceDxQy<nDim, nDist, SysEqn>(this);
37
38 m_bndCnd = new LbBndCnd(this);
40
41 if(grid().isActive()) {
42 this->prepareCommunication();
43 if(m_geometry->m_parallelGeometry) {
44 this->receiveWindowTriangles();
45 }
46 }
47
48 m_log << "noCells(offset) =" << this->noInternalCells() << endl;
49 m_log << "noCells(size) =" << this->m_cells.size() << endl;
50
51#ifdef WAR_NVHPC_PSTL
53#endif
54}
55
59template <MInt nDim, MInt nDist, class SysEqn>
61 TRACE();
62 if(m_isRefined || this->m_adaptation) delete m_interface;
63 delete m_bndCnd;
64}
65
73template <MInt nDim, MInt nDist, class SysEqn>
75 TRACE();
76
77 // MInt distStart, distNeighStart, n1Start, n2Start;
78 // inner loop references
79 const MInt noCells = a_noCells();
80
81 // Required for ported functions, since GPUs cannot access the global variable globalTimeStep
82 const MInt gTS = globalTimeStep;
83 const MInt maxLevel_ = maxLevel();
84
85 maia::parallelFor<true>(0, noCells, [=](MInt i) {
86 if(gTS % IPOW2(maxLevel_ - this->a_level(i)) != 0) return;
87 const MInt lastId = nDist - 1;
88 for(MInt j = 0; j < lastId; ++j) {
89 if(auto n = c_neighborId(i, j); n > -1) {
90 a_oldDistribution(n, j) = a_distribution(i, j);
91 }
92 }
93 a_oldDistribution(i, lastId) = a_distribution(i, lastId);
94 });
95
96 postPropagationSrcTerm();
97 volumeForces();
98
99 if(m_isRefined) {
100 restriction();
101 prolongation();
102 }
103}
104
105
112template <MInt nDim, MInt nDist, class SysEqn>
114 TRACE();
115
116 MInt nghbrId, nghbrId2;
117
118 if(m_isRefined) prolongation();
119
120 for(MInt i = 0; i < a_noCells(); i++) {
121 if((globalTimeStep) % IPOW2(maxLevel() - this->a_level(i)) == 0) {
122 for(MInt j = 0; j < nDist - 1; j += 2) {
123 nghbrId = c_neighborId(i, j);
124 nghbrId2 = c_neighborId(i, j + 1);
125
126 if(nghbrId > -1) a_oldDistribution(nghbrId, j) = a_distribution(i, j);
127 if(nghbrId2 > -1) a_oldDistribution(nghbrId2, j + 1) = a_distribution(i, j + 1);
128 }
129 a_oldDistribution(i, nDist - 1) = a_distribution(i, nDist - 1);
130 }
131 }
132
133 restriction();
134
135 //--
136
137 // #define WRITECELLVALUES
138#ifdef WRITECELLVALUES
139 ofstream ofl;
140
141 if((globalTimeStep) % 40 == 0) {
142 if(domainId() == 7) {
143 ofl.open("x0p75.dat", ios_base::app);
144 ofl << globalTimeStep << " " << a_variable(212707, 0) << " " << a_variable(212707, 1) << " "
145 << a_variable(212707, 2) << " " << a_variable(212707, 3) << endl;
146 ofl.close();
147
148 ofl.open("x1p5.dat", ios_base::app);
149 ofl << globalTimeStep << " " << a_variable(235107, 0) << " " << a_variable(235107, 1) << " "
150 << a_variable(235107, 2) << " " << a_variable(235107, 3) << endl;
151 ofl.close();
152 }
153 }
154#endif
155
156 //--
157}
158
159template <MInt nDim, MInt nDist, class SysEqn>
161 TRACE();
162
163 // MInt distStart, distNeighStart, n1Start, n2Start;
164 // inner loop references
165 const MInt noCells = a_noCells();
166
167 // Required for ported functions, since GPUs cannot access the global variable globalTimeStep
168 const MInt gTS = globalTimeStep;
169 const MInt maxLevel_ = maxLevel();
170
171 maia::parallelFor<true>(0, noCells, [=](MInt i) {
172 if(gTS % IPOW2(maxLevel_ - this->a_level(i)) != 0) return;
173 const MInt lastId = nDist - 1;
174 for(MInt j = 0; j < lastId; ++j) {
175 if(auto n = c_neighborId(i, j); n > -1) {
176 a_oldDistribution(n, j) = a_distribution(i, j);
177 a_oldDistributionThermal(n, j) = a_distributionThermal(i, j);
178 }
179 }
180 a_oldDistribution(i, lastId) = a_distribution(i, lastId);
181 a_oldDistributionThermal(i, lastId) = a_distributionThermal(i, lastId);
182 });
183
184 if(m_isRefined) {
185 restriction();
186 prolongation();
187 }
188}
189
197template <MInt nDim, MInt nDist, class SysEqn>
199 TRACE();
200
201 // MInt distStart, distNeighStart, n1Start, n2Start;
202 // inner loop references
203 const MInt noCells = a_noCells();
204
205 // Required for ported functions, since GPUs cannot access the global variable globalTimeStep
206 const MInt gTS = globalTimeStep;
207 const MInt maxLevel_ = maxLevel();
208
209 maia::parallelFor<true>(0, noCells, [=](MInt i) {
210 if(gTS % IPOW2(maxLevel_ - this->a_level(i)) != 0) return;
211 const MInt lastId = nDist - 1;
212 for(MInt j = 0; j < lastId; ++j) {
213 if(auto n = c_neighborId(i, j); n > -1) {
214 a_oldDistribution(n, j) = a_distribution(i, j);
215 a_oldDistributionTransport(n, j) = a_distributionTransport(i, j);
216 }
217 }
218 a_oldDistribution(i, lastId) = a_distribution(i, lastId);
219 a_oldDistributionTransport(i, lastId) = a_distributionTransport(i, lastId);
220 });
221
222 if(m_isRefined) {
223 restriction();
224 prolongation();
225 }
226}
227
235template <MInt nDim, MInt nDist, class SysEqn>
237 TRACE();
238
239 // MInt distStart, distNeighStart, n1Start, n2Start;
240 // inner loop references
241 const MInt noCells = a_noCells();
242
243 // Required for ported functions, since GPUs cannot access the global variable globalTimeStep
244 const MInt gTS = globalTimeStep;
245 const MInt maxLevel_ = maxLevel();
246
247 maia::parallelFor<true>(0, noCells, [=](MInt i) {
248 if(gTS % IPOW2(maxLevel_ - this->a_level(i)) != 0) return;
249 const MInt lastId = nDist - 1;
250 for(MInt j = 0; j < lastId; ++j) {
251 if(auto n = c_neighborId(i, j); n > -1) {
252 a_oldDistribution(n, j) = a_distribution(i, j);
253 a_oldDistributionThermal(n, j) = a_distributionThermal(i, j);
254 a_oldDistributionTransport(n, j) = a_distributionTransport(i, j);
255 }
256 }
257 a_oldDistribution(i, lastId) = a_distribution(i, lastId);
258 a_oldDistributionThermal(i, lastId) = a_distributionThermal(i, lastId);
259 a_oldDistributionTransport(i, lastId) = a_distributionTransport(i, lastId);
260 });
261
262 if(m_isRefined) {
263 restriction();
264 prolongation();
265 }
266}
267
276template <MInt nDim, MInt nDist, class SysEqn>
278 TRACE();
279
280 MInt nghbrId, nghbrId2;
281
282 if(m_isRefined) prolongation();
283
284 for(MInt i = 0; i < a_noCells(); i++) {
285 if((globalTimeStep) % IPOW2(maxLevel() - this->a_level(i)) == 0) {
286 for(MInt j = 0; j < nDist - 1; j += 2) {
287 nghbrId = c_neighborId(i, j);
288 nghbrId2 = c_neighborId(i, j + 1);
289 if(nghbrId > -1) {
290 a_oldDistribution(nghbrId, j) = a_distribution(i, j);
291 a_oldDistributionThermal(nghbrId, j) = a_distributionThermal(i, j);
292 }
293 if(nghbrId2 > -1) {
294 a_oldDistribution(nghbrId2, j + 1) = a_distribution(i, j + 1);
295 a_oldDistributionThermal(nghbrId2, j + 1) = a_distributionThermal(i, j + 1);
296 }
297 }
298 a_oldDistribution(i, nDist - 1) = a_distribution(i, nDist - 1);
299 a_oldDistributionThermal(i, nDist - 1) = a_distributionThermal(i, nDist - 1);
300 }
301 }
302
303 restriction();
304}
305
313template <MInt nDim, MInt nDist, class SysEqn>
315 TRACE();
316
317 MInt nghbrId, nghbrId2;
318
319 if(m_isRefined) prolongation();
320
321 for(MInt i = 0; i < a_noCells(); i++) {
322 if((globalTimeStep) % IPOW2(maxLevel() - this->a_level(i)) == 0) {
323 for(MInt j = 0; j < nDist - 1; j += 2) {
324 nghbrId = c_neighborId(i, j);
325 nghbrId2 = c_neighborId(i, j + 1);
326 if(nghbrId > -1) {
327 a_oldDistribution(nghbrId, j) = a_distribution(i, j);
328 a_oldDistributionTransport(nghbrId, j) = a_distributionTransport(i, j);
329 }
330 if(nghbrId2 > -1) {
331 a_oldDistribution(nghbrId2, j + 1) = a_distribution(i, j + 1);
332 a_oldDistributionTransport(nghbrId2, j + 1) = a_distributionTransport(i, j + 1);
333 }
334 }
335 a_oldDistribution(i, nDist - 1) = a_distribution(i, nDist - 1);
336 a_oldDistributionTransport(i, nDist - 1) = a_distributionTransport(i, nDist - 1);
337 }
338 }
339
340 restriction();
341}
342
348template <MInt nDim, MInt nDist, class SysEqn>
350 TRACE();
351
352 MInt nghbrId, nghbrId2;
353
354 if(m_isRefined) prolongation();
355
356 for(MInt i = 0; i < a_noCells(); i++) {
357 if((globalTimeStep) % IPOW2(maxLevel() - this->a_level(i)) == 0) {
358 for(MInt j = 0; j < nDist - 1; j += 2) {
359 nghbrId = c_neighborId(i, j);
360 nghbrId2 = c_neighborId(i, j + 1);
361 if(nghbrId > -1) {
362 a_oldDistribution(nghbrId, j) = a_distribution(i, j);
363 a_oldDistributionThermal(nghbrId, j) = a_distributionThermal(i, j);
364 a_oldDistributionTransport(nghbrId, j) = a_distributionTransport(i, j);
365 }
366 if(nghbrId2 > -1) {
367 a_oldDistribution(nghbrId2, j + 1) = a_distribution(i, j + 1);
368 a_oldDistributionThermal(nghbrId2, j + 1) = a_distributionThermal(i, j + 1);
369 a_oldDistributionTransport(nghbrId2, j + 1) = a_distributionTransport(i, j + 1);
370 }
371 }
372 a_oldDistribution(i, nDist - 1) = a_distribution(i, nDist - 1);
373 a_oldDistributionThermal(i, nDist - 1) = a_distributionThermal(i, nDist - 1);
374 a_oldDistributionTransport(i, nDist - 1) = a_distributionTransport(i, nDist - 1);
375 }
376 }
377
378 restriction();
379}
380
381template <MInt nDim, MInt nDist, class SysEqn>
382template <MInt timeStepOffset>
384 // Required for ported functions, since GPUs cannot access the global variable globalTimeStep
385 const MInt gTSmOffset = globalTimeStep - timeStepOffset; // Because collision step is performed one TS earlier
386 const MInt maxLevel_ = maxLevel();
387
388 if(this->isCompressible()) {
389 maia::parallelFor<true>(0, m_currentMaxNoCells, [=](MInt index) {
390 const MInt pCellId = m_activeCellList[index];
391 const MInt lvlDiff = maxLevel_ - a_level(pCellId);
392 if(gTSmOffset % IPOW2(lvlDiff) != 0) return;
393 swap_variables(pCellId);
394#ifdef WAR_NVHPC_PSTL
395 MFloat u[nDim] = {F0};
396 for(MInt d = 0; d < nDim; d++) {
397 u[d] = a_variable(pCellId, d);
398 }
399 MFloat l_rho = a_variable(pCellId, PV->RHO);
400 calculateMacroscopicVariables<true>(pCellId, l_rho, u);
401 for(MInt d = 0; d < nDim; d++) {
402 a_variable(pCellId, d) = u[d];
403 }
404 a_variable(pCellId, PV->RHO) = l_rho;
405#else
406 calculateMacroscopicVariables<true>(pCellId, a_variable(pCellId, PV->RHO), &a_variable(pCellId, PV->U));
407#endif
408 });
409 } else {
410 maia::parallelFor<true>(0, m_currentMaxNoCells, [=](MInt index) {
411 const MInt pCellId = m_activeCellList[index];
412 const MInt lvlDiff = maxLevel_ - a_level(pCellId);
413 if(gTSmOffset % IPOW2(lvlDiff) != 0) return;
414 swap_variables(pCellId);
415#ifdef WAR_NVHPC_PSTL
416 MFloat u[nDim] = {F0};
417 for(MInt d = 0; d < nDim; d++) {
418 u[d] = a_variable(pCellId, d);
419 }
420 MFloat l_rho = a_variable(pCellId, PV->RHO);
421 calculateMacroscopicVariables(pCellId, l_rho, u);
422 for(MInt d = 0; d < nDim; d++) {
423 a_variable(pCellId, d) = u[d];
424 }
425 a_variable(pCellId, PV->RHO) = l_rho;
426#else
427 calculateMacroscopicVariables(pCellId, a_variable(pCellId, PV->RHO), &a_variable(pCellId, PV->U));
428#endif
429 });
430 }
431}
432
433template <MInt nDim, MInt nDist, class SysEqn>
435 updateVariablesFromOldDist_<0>();
436}
437
438template <MInt nDim, MInt nDist, class SysEqn>
440 // TODO labels:LB @johannes/julian: You made this step after propagation. Preference against here?
441 // if(this->m_isInitRun) {
442 // this->initRunCorrection();
443 // } else {
444 updateVariablesFromOldDist_<1>();
445 // }
446}
447
455template <MInt nDim, MInt nDist, class SysEqn>
457 if(string2enum(solverMethod()) == MAIA_LATTICE_BGK_TOTALENERGY)
458 return; // in this collision step the forcing is added differently. There seems to be no easy way to unify the
459 // methods.
460 if(m_controlVelocity) controlVelocity();
461
462 // Required for ported functions, since GPUs cannot access the global variable globalTimeStep
463 const MInt gTS = globalTimeStep;
464 const MInt maxLevel_ = maxLevel();
465
466 // TODO labels:LB Move to lb source terms?
467 if(this->m_externalForcing) {
468 // add forcing term
469 maia::parallelFor<true>(0, m_currentMaxNoCells, [=](MInt index) {
470 const MInt pCellId = m_activeCellList[index];
471 const MInt lvlDiff = maxLevel_ - a_level(pCellId);
472 if((gTS) % IPOW2(lvlDiff) != 0) return;
473 for(MInt j = 0; j < nDist - 1; j++) {
474 a_oldDistribution(pCellId, j) += FPOW2(maxLevel_ - this->a_level(pCellId)) * m_Fext[j];
475 }
476 });
477 }
478
479 if(m_isEELiquid && m_EELiquid.gravity) {
480 maia::parallelFor<true>(0, m_currentMaxNoCells, [=](MInt index) {
481 const MInt pCellId = m_activeCellList[index];
482 const MInt lvlDiff = maxLevel_ - a_level(pCellId);
483 if((gTS) % IPOW2(lvlDiff) != 0) return;
484 const MFloat alpha = a_alphaGasLim(pCellId);
485
486 for(MInt j = 0; j < nDist - 1; j++) {
487 // gravity included in m_EELiquid.Fg
488 // *3.0 is 1/c_s^2 see Haenel_MolekulareGasdynamik Eq. (9.65)
489 // -= because the effects of gravity are introduced through buoyancy
490 a_oldDistribution(pCellId, j) -= FPOW2(maxLevel_ - this->a_level(pCellId)) * m_EELiquid.Fg[j] * alpha;
491 }
492 });
493 }
494}
495
503template <MInt nDim, MInt nDist, class SysEqn>
505 if(globalTimeStep % m_velocityControl.interval != 0) return;
506
507 averageGlobalVelocity(
508 m_velocityControl.dir); // m_velocityControl.dir defines the component of the velocity that is averaged
509 const MFloat velocityGoal = m_Ma / F1BCS;
510 if((m_velocityControl.lastGlobalAvgV > 5.0 * velocityGoal) || (m_velocityControl.lastGlobalAvgV < 0.0)
511 || !std::isfinite(m_velocityControl.lastGlobalAvgV)) {
512 if(domainId() == 0) cerr << "TS " << globalTimeStep << " avVel " << m_velocityControl.lastGlobalAvgV << endl;
513 m_log << "TS " << globalTimeStep << " avVel " << m_velocityControl.lastGlobalAvgV << endl;
514 TERMM(1, "Velocity control failed!");
515 }
516 const MFloat error = (m_velocityControl.lastGlobalAvgV - velocityGoal) / velocityGoal;
517 m_velocityControl.integratedError += (error + m_velocityControl.previousError) / 2.0 * m_velocityControl.interval;
518 m_velocityControl.derivedError = (error - m_velocityControl.previousError) / m_velocityControl.interval;
519
520 MFloat controlSignal = m_velocityControl.KT
521 * (error + F1 / m_velocityControl.KI * m_velocityControl.integratedError
522 + m_velocityControl.KD * m_velocityControl.derivedError);
523
524 controlSignal = mMax(mMin(controlSignal, 100.0), -100.0);
525
526 m_volumeAccel[m_velocityControl.dir] =
527 m_volumeAccelBase[m_velocityControl.dir] - controlSignal * m_volumeAccelBase[m_velocityControl.dir];
528
529 this->initVolumeForces();
530
531 stringstream ss;
532 ss << "Average velocity at TS " << globalTimeStep << " is " << m_velocityControl.lastGlobalAvgV
533 << " (goal: " << velocityGoal << ") accel set to: [" << m_volumeAccel[0] << ", " << m_volumeAccel[1];
534 if(nDim == 3) {
535 ss << ", " << m_volumeAccel[2];
536 }
537 ss << "] (base was [" << m_volumeAccelBase[0] << ", " << m_volumeAccelBase[1];
538 if(nDim == 3) {
539 ss << ", " << m_volumeAccelBase[2];
540 }
541 ss << "])" << endl;
542 ss << "Error: " << error << " previousError: " << m_velocityControl.previousError
543 << " integratedError: " << m_velocityControl.integratedError
544 << " derivedError: " << m_velocityControl.derivedError << endl;
545 if(domainId() == 0) {
546 cerr << ss.str();
547 }
548 m_log << ss.str();
549
550 m_velocityControl.previousError = error;
551}
552
562template <MInt nDim, MInt nDist, class SysEqn>
564 MFloat sumV[2] = {}; // Sum of {velocity * cellVolume, cellVolume}
565 MFloat c1 = 0.0;
566
567 // the velocity component of sumV is summed by Kahan summation because of potential for different orders of magnitude
568 // for the cell volume normal summation is used
569 for(MInt cellId = 0; cellId < this->grid().noInternalCells(); cellId++) {
570 if(this->c_noChildren(cellId) != 0) continue;
571 const MFloat cellVolume = this->grid().cellVolumeAtLevel(this->c_level(cellId));
572
573 const MFloat y1 = a_variable(cellId, dir) * cellVolume - c1;
574 const MFloat t1 = sumV[0] + y1;
575 c1 = (t1 - sumV[0]) - y1;
576 sumV[0] = t1;
577 sumV[1] += cellVolume;
578 }
579 MPI_Allreduce(MPI_IN_PLACE, &sumV, 2, maia::type_traits<MFloat>::mpiType(), MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE",
580 "sumV");
581
582 m_velocityControl.lastGlobalAvgV = sumV[0] / sumV[1];
583}
584
585template <MInt nDim, MInt nDist, class SysEqn>
586template <MBool useSmagorinsky>
588 TRACE();
589 std::stringstream ss;
590 if constexpr(useSmagorinsky) {
591 ss << "CLB_SMAGORINSKY collision step not defined for d" << nDim << "q" << nDist << " !";
592 } else {
593 ss << "CLB collision step not defined for d" << nDim << "q" << nDist << " !";
594 }
595 TERMM(1, ss.str());
596}
597
598template <>
599template <>
600void LbSolverDxQy<2, 9, maia::lb::LbSysEqnIncompressible<2, 9>>::clb_collision_step_base<false>() {
601 TRACE();
602 constexpr MInt nDist = 9;
603
604 constexpr MLongFloat K[9][9] = {
605 {1.0, 0.0, 0.0, -4.0, 0.0, 0.0, 0.0, 0.0, 4.0}, {1.0, -1.0, 1.0, 2.0, 0.0, 1.0, -1.0, 1.0, 1.0},
606 {1.0, -1.0, 0.0, -1.0, 1.0, 0.0, 0.0, -2.0, -2.0}, {1.0, -1.0, -1.0, 2.0, 0.0, -1.0, 1.0, 1.0, 1.0},
607 {1.0, 0.0, -1.0, -1.0, -1.0, 0.0, -2.0, 0.0, -2.0}, {1.0, 1.0, -1.0, 2.0, 0.0, 1.0, 1.0, -1.0, 1.0},
608 {1.0, 1.0, 0.0, -1.0, 1.0, 0.0, 0.0, 2.0, -2.0}, {1.0, 1.0, 1.0, 2.0, 0.0, -1.0, -1.0, -1.0, 1.0},
609 {1.0, 0.0, 1.0, -1.0, -1.0, 0.0, 2.0, 0.0, -2.0}};
610
611 for(MInt id = 0; id < a_noCells(); id++) {
612 if((globalTimeStep - 1) % IPOW2(maxLevel() - this->a_level(id)) == 0) {
613 m_nu = m_Ma * LBCS / m_Re * m_referenceLength * FFPOW2(maxLevel() - this->a_level(id));
614
615 MLongFloat omega[9] = {1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0};
616 m_omega = 2.0 / (1.0 + 6.0 * m_nu);
617 omega[4] = m_omega;
618 omega[5] = m_omega;
619
620 swap_variables(id);
621
622 // Calculation of macroscopic variables + forcing term
623 for(MInt j = 0; j < nDist; j++) {
624 a_variable(id, PV->RHO) += a_oldDistribution(id, j);
625 }
626 const MFloat rho = a_variable(id, PV->RHO);
627
628 a_variable(id, PV->U) = (a_oldDistribution(id, 1) + a_oldDistribution(id, 4) + a_oldDistribution(id, 5)
629 - a_oldDistribution(id, 7) - a_oldDistribution(id, 6) - a_oldDistribution(id, 0))
630 / rho;
631
632 a_variable(id, PV->V) = (a_oldDistribution(id, 7) + a_oldDistribution(id, 3) + a_oldDistribution(id, 4)
633 - a_oldDistribution(id, 6) - a_oldDistribution(id, 2) - a_oldDistribution(id, 5))
634 / rho;
635
636 const MFloat u = a_variable(id, PV->U);
637 const MFloat v = a_variable(id, PV->V);
638
639 const MFloat r = a_oldDistribution(id, 8);
640 const MFloat nw = a_oldDistribution(id, 7);
641 const MFloat w = a_oldDistribution(id, 0);
642 const MFloat sw = a_oldDistribution(id, 6);
643 const MFloat s = a_oldDistribution(id, 2);
644 const MFloat se = a_oldDistribution(id, 5);
645 const MFloat e = a_oldDistribution(id, 1);
646 const MFloat ne = a_oldDistribution(id, 4);
647 const MFloat n = a_oldDistribution(id, 3);
648
649 // Calculate equilibrium moments...
650 MLongFloat keq[9];
651 keq[0] = 0.0;
652 keq[1] = 0.0;
653 keq[2] = 0.0;
654 keq[3] = omega[3] * (rho * (u * u + v * v) - e - n - s - w - 2.0 * (se + sw + ne + nw - F1B3 * rho)) / 12.0;
655
656 keq[4] = omega[4] * (n + s - e - w + rho * (u * u - v * v)) / 4.0;
657
658 keq[5] = omega[5] * ((ne + sw - nw - se) - u * v * rho) / 4.0;
659
660 keq[6] = omega[6]
661 * (-1.0
662 * ((se + sw - ne - nw - 2 * u * u * v * rho + v * (rho - n - s - r)) / 4.0
663 + u / 2.0 * (ne - nw - se + sw)))
664 - v / 2.0 * (-3.0 * keq[3] - keq[4]) - 2.0 * u * keq[5];
665 keq[7] = omega[7]
666 * (-1.0
667 * ((sw + nw - se - ne - 2 * v * v * u * rho + u * (rho - w - e - r)) / 4.0
668 + v / 2.0 * (ne - nw - se + sw) / 2.0))
669 - u / 2.0 * (-3.0 * keq[3] + keq[4]) - 2.0 * v * keq[5];
670 keq[8] = omega[8]
671 * (F1B4
672 * (F1B9 * rho - ne - nw - se - sw + 2.0 * (u * (ne - nw + se - sw) + v * (ne + nw - se - sw))
673 + 4.0 * u * v * (nw - ne + se - sw) - u * u * (n + ne + nw + s + se + sw)
674 + v * v * (3.0 * u * u * rho - e - ne - nw - se - sw - w)))
675 - 2.0 * keq[3] - 2.0 * u * keq[7] - 2.0 * v * keq[6] + 4 * u * v * keq[5]
676 - (1.5 * keq[3] - F1B2 * keq[4]) * (u * u + v * v);
677
678 // Matrix vector multiplication (must be optimized)
679 MLongFloat k[9];
680 for(MInt l = 0; l < 9; l++) {
681 k[l] = std::inner_product(&K[l][0], &K[l][9], &keq[0], F0);
682 }
683
684 a_distribution(id, 8) = a_oldDistribution(id, 8) + k[0];
685 a_distribution(id, 7) = a_oldDistribution(id, 7) + k[1];
686 a_distribution(id, 0) = a_oldDistribution(id, 0) + k[2];
687 a_distribution(id, 6) = a_oldDistribution(id, 6) + k[3];
688 a_distribution(id, 2) = a_oldDistribution(id, 2) + k[4];
689 a_distribution(id, 5) = a_oldDistribution(id, 5) + k[5];
690 a_distribution(id, 1) = a_oldDistribution(id, 1) + k[6];
691 a_distribution(id, 4) = a_oldDistribution(id, 4) + k[7];
692 a_distribution(id, 3) = a_oldDistribution(id, 3) + k[8];
693 }
694 }
695}
696
697template <>
698template <>
699void LbSolverDxQy<3, 19, maia::lb::LbSysEqnIncompressible<3, 19>>::clb_collision_step_base<false>() {
700 TRACE();
701 constexpr MInt nDist = 19;
702
703 for(MInt i = 0; i < m_currentMaxNoCells; i++) {
704 const MInt pCellId = m_activeCellList[i];
705
706 if((globalTimeStep - 1) % IPOW2(maxLevel() - this->a_level(pCellId)) == 0) {
707 m_nu = m_Ma * LBCS / m_Re * m_referenceLength;
708
709 m_omega = 2.0 / (1.0 + 6.0 * m_nu * FFPOW2(maxLevel() - this->a_level(pCellId)));
710 MFloat omega = m_omega;
711
712 swap_variables(pCellId);
713
714 // Calculate macroscopic variables
715 a_variable(pCellId, PV->RHO) = 0.0;
716 for(MInt j = 0; j < nDist; j++) {
717 a_variable(pCellId, PV->RHO) += a_oldDistribution(pCellId, j);
718 }
719
720 a_variable(pCellId, PV->U) = 0.0;
721 for(MInt j = 0; j < Ld::dxQyFld(); j++) {
722 a_variable(pCellId, PV->U) += a_oldDistribution(pCellId, Ld::pFld(0, j));
723 a_variable(pCellId, PV->U) -= a_oldDistribution(pCellId, Ld::nFld(0, j));
724 }
725 a_variable(pCellId, PV->U) /= a_variable(pCellId, PV->RHO);
726
727 a_variable(pCellId, PV->V) = 0.0;
728 for(MInt j = 0; j < Ld::dxQyFld(); j++) {
729 a_variable(pCellId, PV->V) += a_oldDistribution(pCellId, Ld::pFld(1, j));
730 a_variable(pCellId, PV->V) -= a_oldDistribution(pCellId, Ld::nFld(1, j));
731 }
732 a_variable(pCellId, PV->V) /= a_variable(pCellId, PV->RHO);
733
734 a_variable(pCellId, PV->W) = 0.0;
735 for(MInt j = 0; j < Ld::dxQyFld(); j++) {
736 a_variable(pCellId, PV->W) += a_oldDistribution(pCellId, Ld::pFld(2, j));
737 a_variable(pCellId, PV->W) -= a_oldDistribution(pCellId, Ld::nFld(2, j));
738 }
739 a_variable(pCellId, PV->W) /= a_variable(pCellId, PV->RHO);
740
741 const MFloat R = a_oldDistribution(pCellId, 18);
742 const MFloat Nw = a_oldDistribution(pCellId, 7);
743 const MFloat W = a_oldDistribution(pCellId, 0);
744 const MFloat Sw = a_oldDistribution(pCellId, 6);
745 const MFloat S = a_oldDistribution(pCellId, 2);
746 const MFloat Se = a_oldDistribution(pCellId, 8);
747 const MFloat E = a_oldDistribution(pCellId, 1);
748 const MFloat Ne = a_oldDistribution(pCellId, 9);
749 const MFloat N = a_oldDistribution(pCellId, 3);
750 const MFloat Nf = a_oldDistribution(pCellId, 17);
751 const MFloat Nb = a_oldDistribution(pCellId, 16);
752 const MFloat Sf = a_oldDistribution(pCellId, 15);
753 const MFloat Sb = a_oldDistribution(pCellId, 14);
754 const MFloat Ef = a_oldDistribution(pCellId, 13);
755 const MFloat Eb = a_oldDistribution(pCellId, 12);
756 const MFloat Wf = a_oldDistribution(pCellId, 11);
757 const MFloat Wb = a_oldDistribution(pCellId, 10);
758 const MFloat F = a_oldDistribution(pCellId, 5);
759 const MFloat B = a_oldDistribution(pCellId, 4);
760
761 const MFloat rho = Nw + W + Sw + S + Se + E + Ne + N + R + Nf + Nb + Sf + Sb + Ef + Eb + Wf + Wb + F + B;
762 const MFloat pi_x = (Ne + E + Se + Ef + Eb - Nw - W - Sw - Wf - Wb);
763 const MFloat pi_y = (Ne + N + Nw + Nf + Nb - Se - S - Sw - Sf - Sb);
764 const MFloat pi_z = (Nf + Sf + Wf + Ef + F - Nb - Sb - Wb - Eb - B);
765 const MFloat vv_x = pi_x / rho;
766 const MFloat vv_y = pi_y / rho;
767 const MFloat vv_z = pi_z / rho;
768 const MFloat vx2 = vv_x * vv_x;
769 const MFloat vy2 = vv_y * vv_y;
770 const MFloat vz2 = vv_z * vv_z;
771 const MFloat uxy = (omega * (Ne - Nw - Se + Sw + vv_x * vv_y * rho - pi_x * vv_y - pi_y * vv_x) * 0.25);
772 const MFloat uxz = (omega * (-Eb + Ef + Wb - Wf + vv_x * vv_z * rho - pi_x * vv_z - pi_z * vv_x) * 0.25);
773 const MFloat uyz = (omega * (-Nb + Nf + Sb - Sf + vv_z * vv_y * rho - pi_z * vv_y - pi_y * vv_z) * 0.25);
774
775 const MFloat vxy = (omega * (1. / 6.)
776 * (-B - E - F + Nb + Ne + Nf + Nw + Sb + Se + Sf + Sw - W + 2 * (-Eb - Ef + N + S - Wb - Wf)
777 + 2 * (-2 * pi_y * vv_y + pi_x * vv_x + pi_z * vv_z) - rho * (vz2 - 2 * vy2 + vx2)));
778 const MFloat vxz = (omega * (1. / 6.)
779 * (-E + Eb + Ef - N + Nb + Nf - S + Sb + Sf - W + Wb + Wf + 2 * (B + F - Ne - Nw - Se - Sw)
780 + 2 * (-2 * pi_z * vv_z + pi_x * vv_x + pi_y * vv_y) - rho * (vx2 + vy2 - 2 * vz2)));
781 const MFloat pe = ((1. / 126.)
782 * (-B - E - F - N - S - W + 2 * (-Eb - Ef - Nb - Ne - Nf - Nw - Sb - Se - Sf - Sw - Wb - Wf)
783 + (rho + vv_y * (2 * pi_y - vv_y * rho) + vv_z * (2 * pi_z - vv_z * rho)
784 + vv_x * (2 * pi_x - vv_x * rho))));
785
786 const MFloat UXY = -Ne + Nw + Se - Sw + 4 * uxy;
787 const MFloat UXZ = Eb - Ef - Wb + Wf + 4 * uxz;
788 const MFloat UYZ = Nb - Nf - Sb + Sf + 4 * uyz;
789
790 const MFloat x = ((0.125
791 * (Nw + Sw + Wf + Wb - Eb - Ef - Ne - Se
792 + vv_x
793 * (B + Eb + Ef + 84 * pe + F + N + Ne + Nw + S + Se + Sw + Wb + Wf
794 + 2 * (Nb + Nf + Sb + Sf - vxy - vxz)))
795 + 0.25 * (-vv_y * UXY - vv_z * UXZ) - 0.25 * vv_x * (vv_y * pi_y + vv_z * pi_z)
796 + 0.125 * (vy2 + vz2) * (vv_x * rho - pi_x)));
797 const MFloat y = ((0.125
798 * (Sb + Sf + Se + Sw - Nw - Ne - Nf - Nb
799 + vv_y
800 * (B + E + 84 * pe + F + Nb + Ne + Nf + Nw + Sb + Se + Sf + Sw + W
801 + 2 * (Eb + Ef + Wb + Wf + vxy)))
802 + 0.25 * (-vv_x * UXY - vv_z * UYZ) - 0.25 * vv_y * (vv_z * pi_z + vv_x * pi_x)
803 + 0.125 * (vx2 + vz2) * (vv_y * rho - pi_y)));
804 const MFloat z = ((0.125
805 * (Eb + Nb + Sb + Wb - Ef - Nf - Sf - Wf
806 + vv_z
807 * (E + Eb + Ef + N + Nb + Nf + S + Sb + Sf + W + Wb + Wf + 84 * pe
808 + 2 * (Ne + Nw + Se + Sw + vxz)))
809 + 0.25 * (-vv_x * UXZ - vv_y * UYZ) - 0.25 * vv_z * (vv_x * pi_x + vv_y * pi_y)
810 + 0.125 * (vx2 + vy2) * (vv_z * rho - pi_z)));
811
812 const MFloat xxx = ((0.125
813 * (Eb + Ef - Ne + Nw - Se + Sw - Wb - Wf
814 + vv_x * (-B - Eb - Ef - F + N + Ne + Nw + S + Se + Sw - Wb - Wf + 2 * (vxz - vxy)))
815 + 0.25 * (vv_z * UXZ - vv_y * UXY + vv_x * (vv_z * pi_z - vv_y * pi_y))
816 + 0.125 * ((pi_x - vv_x * rho) * (vz2 - vy2))));
817 const MFloat yyy =
818 ((0.125
819 * (Ne - Nb - Nf + Nw + Sb - Se + Sf - Sw
820 + vv_y * (-E + B + F + Nb - Ne + Nf - Nw + Sb - Se + Sf - Sw - W + 2 * (-vxy - 2 * vxz)))
821 + 0.25 * (vv_x * UXY - vv_z * UYZ + vv_y * (vv_x * pi_x - vv_z * pi_z))
822 + 0.125 * ((pi_y - vv_y * rho) * (vx2 - vz2))));
823 const MFloat zzz =
824 ((0.125
825 * (Eb - Ef - Nb + Nf - Sb + Sf + Wb - Wf
826 + vv_z * (E + Eb + Ef - N - Nb - Nf - S - Sb - Sf + W + Wb + Wf + 2 * (vxz + 2 * vxy)))
827 + 0.25 * (vv_y * UYZ - vv_x * UXZ + vv_z * (vv_y * pi_y - vv_x * pi_x))
828 + 0.125 * ((pi_z - vv_z * rho) * (vy2 - vx2))));
829
830 // xyz=(0.125*(Neb-Nef-Nwb+Nwf-Seb+Sef+Swb-Swf-vv_x*UYZ-vv_y*UXZ-vv_z*UXY+rho*vv_x*vv_y*vv_z-(vv_x*vv_y*pi_z+vv_x*pi_y*vv_z+pi_x*vv_y*vv_z)));
831
832 const MFloat X_ = (Eb + Ef + Ne - Nw + Se - Sw - Wb - Wf + 8 * x);
833 const MFloat Y_ = (Nb + Ne + Nf + Nw - Sb - Se - Sf - Sw + 8 * y);
834 const MFloat Z_ = (Ef - Eb - Nb + Nf - Sb + Sf - Wb + Wf + 8 * z);
835
836 // XnXXX=Eb+Ef-Wb-Wf+4*(x-xxx);
837 // XpXXX=Ne-Nw+Se-Sw+4*(x+xxx);
838 // YnYYY=Ne+Nw-Se-Sw+4*(y-yyy);
839 // YpYYY=Nb+Nf-Sb-Sf+4*(y+yyy);
840 // ZnZZZ=-Nb+Nf-Sb+Sf+4*(z-zzz);
841 // ZpZZZ=-Eb+Ef-Wb+Wf+4*(z+zzz);
842
843 // XYZ= 8*xyz;
844 // EPa=-42*pe-E-Eb-Ef-Ne-Nw-Se-Sw-W-Wb-Wf-2*(vxy+vxz);
845 // EPb=-42*pe-B-Eb-Ef-F-Nb-Nf-Sb-Sf-Wb-Wf+2*vxz;
846 // EPc=-42*pe-N-Nb-Ne-Nf-Nw-S-Sb-Se-Sf-Sw+2*vxy;
847
848 const MFloat p = ((1. / 12.)
849 * (rho / (3.) - 96 * pe - Eb - Ef - Nb - Ne - Nf - Nw - Sb - Se - Sf - Sw - Wb - Wf
850 + 2 * (+vv_x * X_ + vv_y * Y_ + vv_z * Z_)
851 + vx2
852 * (-84 * pe - B - Eb - Ef - F - N - Ne - Nw - S - Se - Sw - Wb - Wf
853 + 2 * (vxy + vxz - Nb - Nf - Sb - Sf))
854 + vy2
855 * (-84 * pe - B - E - F - Nb - Ne - Nf - Nw - Sb - Se - Sf - Sw - W
856 + 2 * (-vxy - Eb - Ef - Wb - Wf))
857 + vz2
858 * (-84 * pe - E - Eb - Ef - N - Nb - Nf - S - Sb - Sf - W - Wb - Wf
859 + 2 * (-vxz - Ne - Nw - Se - Sw))
860 + 4 * (vv_x * vv_y * UXY + vv_x * vv_z * UXZ + vv_y * vv_z * UYZ)
861 - rho * (vx2 * vy2 + vx2 * vz2 + vy2 * vz2)
862 + 2 * (pi_y * vv_y * (vx2 + vz2) + pi_x * vv_x * (vy2 + vz2) + pi_z * vv_z * (vx2 + vy2))));
863
864 const MFloat a =
865 ((1. / 12.)
866 * (-Eb - Ef - Ne - Nw - Se - Sw - Wb - Wf
867 + 2
868 * (Nb + Nf + Sb + Sf + vv_x * X_
869 + vv_y * (Ne + Nw - Se - Sw + 2 * (Sf + Sb - Nb - Nf - 2 * y - 6 * yyy))
870 + vv_z * (Ef - Eb - Wb + Wf + 2 * (Nb - Nf + Sb - Sf - 2 * z + 6 * zzz)))
871 + vx2
872 * (-B - Eb - Ef - F - N - Ne - Nw - S - Se - Sw - Wb - Wf - 84 * pe
873 - 2 * (Nb + Nf + Sb + Sf - vxy - vxz))
874 + vy2
875 * (Eb - E + Ef - Ne - Nw - Se - Sw - W + Wb + Wf + 42 * pe
876 + 2 * (B + F + Nb + Nf + Sb + Sf - vxy - 3 * vxz))
877 + vz2
878 * (Ne - E - Eb - Ef + Nw + Se + Sw - W - Wb - Wf + 42 * pe
879 + 2 * (N + Nb + Nf + S + Sb + Sf - vxz - 3 * vxy))
880 + 4 * (vv_x * (vv_y * UXY + vv_z * UXZ)) - 8 * vv_y * vv_z * UYZ
881 + (2 * vy2 * vz2 - vx2 * (vy2 + vz2)) * rho
882 + 2 * (pi_y * vv_y * (vx2 - 2 * vz2) + pi_z * vv_z * (vx2 - 2 * vy2) + pi_x * vv_x * (vy2 + vz2))));
883 const MFloat c =
884 ((1. / 12.)
885 * (-Nb - Ne - Nf - Nw - Sb - Se - Sf - Sw
886 + 2
887 * (Eb + Ef + Wb + Wf + vv_x * (Ne - Nw + Se - Sw + 2 * (Wb + Wf - Eb - Ef - 2 * x + 6 * xxx))
888 + vv_y * Y_ + vv_z * (Nf - Nb - Sb + Sf + 2 * (Eb - Ef + Wb - Wf - 2 * z - 6 * zzz)))
889 + vx2
890 * (Nb - N - Ne + Nf - Nw - S + Sb - Se + Sf - Sw + 42 * pe
891 + 2 * (B + Eb + Ef + F + Wb + Wf + vxy - 2 * vxz))
892 - vy2 * (B + E + F + Nb + Ne + Nf + Nw + Sb + Se + Sf + Sw + W + 84 * pe + 2 * (Eb + Ef + Wb + Wf + vxy))
893 + vz2
894 * (Ne - N - Nb - Nf + Nw - S - Sb + Se - Sf + Sw + 42 * pe
895 + 2 * (E + Eb + Ef + W + Wb + Wf + 3 * vxy + 2 * vxz))
896 + 4 * vv_y * (vv_x * UXY + vv_z * UYZ) - 8 * vv_x * vv_z * UXZ + (2 * vx2 * vz2 - (vx2 + vz2) * vy2) * rho
897 + 2 * (pi_x * vv_x * (vy2 - 2 * vz2) + pi_z * vv_z * (vy2 - 2 * vx2) + pi_y * vv_y * (vx2 + vz2))));
898
899 a_distribution(pCellId, 18) = R + (12 * p - 30 * pe);
900 a_distribution(pCellId, 7) = Nw + c + a - xxx - yyy - x + y + uxy + p + 8 * pe;
901 a_distribution(pCellId, 0) = W - 2 * a + 4 * x - 11 * pe + vxy + vxz - 4 * p;
902 a_distribution(pCellId, 6) = Sw + a + c - xxx + yyy - x - y - uxy + p + 8 * pe;
903 a_distribution(pCellId, 2) = S - 2 * c + 4 * y - 11 * pe - vxy - 4 * p;
904 a_distribution(pCellId, 8) = Se + a + c + xxx + yyy + x - y + uxy + p + 8 * pe;
905 a_distribution(pCellId, 1) = E - 2 * a - 4 * x - 11 * pe + vxy + vxz - 4 * p;
906 a_distribution(pCellId, 9) = Ne + c + a + x + y + xxx - yyy - uxy + p + 8 * pe;
907 a_distribution(pCellId, 3) = N - 2 * c - 4 * y - 11 * pe - vxy - 4 * p; // s_n;
908 a_distribution(pCellId, 17) = Nf - a + yyy - zzz + y + z - uyz + p + 8 * pe;
909 a_distribution(pCellId, 16) = Nb - a + yyy + zzz + y - z + uyz + p + 8 * pe;
910 a_distribution(pCellId, 15) = Sf - a - yyy - zzz - y + z + uyz + p + 8 * pe;
911 a_distribution(pCellId, 14) = Sb - a - yyy + zzz - y - z - uyz + p + 8 * pe;
912 a_distribution(pCellId, 13) = Ef - c - xxx + zzz + x + z - uxz + p + 8 * pe;
913 a_distribution(pCellId, 12) = Eb - c - xxx - zzz + x - z + uxz + p + 8 * pe;
914 a_distribution(pCellId, 11) = Wf - c + xxx + zzz - x + z + uxz + p + 8 * pe;
915 a_distribution(pCellId, 10) = Wb - c + xxx - zzz - x - z - uxz + p + 8 * pe;
916 a_distribution(pCellId, 5) = F + 2 * a + 2 * c - 4 * z - 11 * pe - vxz - 4 * p;
917 a_distribution(pCellId, 4) = B + 2 * a + 2 * c + 4 * z - 11 * pe - vxz - 4 * p;
918 }
919 }
920 if(m_calculateDissipation && globalTimeStep % m_solutionInterval == 0) {
921 calculateDissipation();
922 }
923}
924
925template <>
926template <MBool useSmagorinsky>
928 TRACE();
929 constexpr MInt nDist = 27;
930 constexpr MInt nDim = 3;
931 constexpr MInt nDimSqr = 9;
932
933 [[maybe_unused]] constexpr MFloat C_s = 0.1;
934
935 for(MInt i = 0; i < m_currentMaxNoCells; i++) {
936 const MInt pCellId = m_activeCellList[i];
937
938 if((globalTimeStep - 1) % IPOW2(maxLevel() - this->a_level(pCellId)) == 0) {
939 m_nu = m_Ma * LBCS / m_Re * m_referenceLength;
940
941 m_omega = 2.0 / (1.0 + 6.0 * m_nu * FFPOW2(maxLevel() - this->a_level(pCellId)));
942 swap_variables(pCellId);
943
944 // Calculate macroscopic variables
945 a_variable(pCellId, PV->RHO) = 0.0;
946 for(MInt j = 0; j < nDist; j++) {
947 a_variable(pCellId, PV->RHO) += a_oldDistribution(pCellId, j);
948 }
949
950 a_variable(pCellId, PV->U) = 0.0;
951 for(MInt j = 0; j < Ld::dxQyFld(); j++) {
952 a_variable(pCellId, PV->U) += a_oldDistribution(pCellId, Ld::pFld(0, j));
953 a_variable(pCellId, PV->U) -= a_oldDistribution(pCellId, Ld::nFld(0, j));
954 }
955 a_variable(pCellId, PV->U) /= a_variable(pCellId, PV->RHO);
956
957 a_variable(pCellId, PV->V) = 0.0;
958 for(MInt j = 0; j < Ld::dxQyFld(); j++) {
959 a_variable(pCellId, PV->V) += a_oldDistribution(pCellId, Ld::pFld(1, j));
960 a_variable(pCellId, PV->V) -= a_oldDistribution(pCellId, Ld::nFld(1, j));
961 }
962 a_variable(pCellId, PV->V) /= a_variable(pCellId, PV->RHO);
963
964 a_variable(pCellId, PV->W) = 0.0;
965 for(MInt j = 0; j < Ld::dxQyFld(); j++) {
966 a_variable(pCellId, PV->W) += a_oldDistribution(pCellId, Ld::pFld(2, j));
967 a_variable(pCellId, PV->W) -= a_oldDistribution(pCellId, Ld::nFld(2, j));
968 }
969 a_variable(pCellId, PV->W) /= a_variable(pCellId, PV->RHO);
970
971 if constexpr(useSmagorinsky) {
972 // Calculation of equilibrium and non-equilibrium distribution
973 std::array<MFloat, nDist> eqDist{};
974 std::array<MFloat, nDist> d{};
975 std::array<MFloat, nDim> u{};
976 for(MInt dim = 0; dim < nDim; dim++) {
977 u[dim] = a_variable(pCellId, dim);
978 }
979 eqDist = getEqDists(a_variable(pCellId, PV->RHO), u.data());
980
981 for(MInt j = 0; j < nDist; j++) {
982 d[j] = a_oldDistribution(pCellId, j) - eqDist[j];
983 }
984
985 // Calculation of strain rate tensor (stress tensor)
986 std::array<MFloat, nDimSqr> Q{};
987 Q[0] = F2B3
988 * (d[0] + d[1] + d[6] + d[7] + d[8] + d[9] + d[10] + d[11] + d[12] + d[13] + d[18] + d[19] + d[20]
989 + d[21] + d[22] + d[23] + d[24] + d[25])
990 - F1B3 * (d[2] + d[3] + d[4] + d[5] + d[14] + d[15] + d[16] + d[17] + d[26]);
991 Q[1] = (d[6] - d[7] - d[8] + d[9] + d[18] + d[19] - d[20] - d[21] - d[22] - d[23] + d[24] + d[25]);
992 Q[2] = (d[10] - d[11] - d[12] + d[13] + d[18] - d[19] + d[20] - d[21] - d[22] + d[23] - d[24] + d[25]);
993 Q[3] = Q[1];
994 Q[4] = F2B3
995 * (d[2] + d[3] + d[6] + d[7] + d[8] + d[9] + d[14] + d[15] + d[16] + d[17] + d[18] + d[19] + d[20]
996 + d[21] + d[22] + d[23] + d[24] + d[25])
997 - F1B3 * (d[0] + d[1] + d[4] + d[5] + d[10] + d[11] + d[12] + d[13] + d[26]);
998 Q[5] = (d[14] - d[15] - d[16] + d[17] + d[18] - d[19] - d[20] + d[21] + d[22] - d[23] - d[24] + d[25]);
999 Q[6] = Q[2];
1000 Q[7] = Q[5];
1001 Q[8] = F2B3
1002 * (d[4] + d[5] + d[10] + d[11] + d[12] + d[13] + d[14] + d[15] + d[16] + d[17] + d[18] + d[19]
1003 + d[20] + d[21] + d[22] + d[23] + d[24] + d[25])
1004 - F1B3 * (d[0] + d[1] + d[2] + d[3] + d[6] + d[7] + d[8] + d[9] + d[26]);
1005
1006 const MFloat Q_mean = sqrt(2.0 * std::inner_product(&Q[0], &Q[nDimSqr], &Q[0], .0));
1007
1008 // eddy viscosity
1009 const MFloat nu_t = C_s * C_s * Q_mean;
1010
1011 m_nu = m_Ma * LBCS / m_Re * m_referenceLength;
1012 m_nu += nu_t; // this has to adapted for refined grids !!!
1013 m_omega = 2.0 / (1.0 + 6.0 * m_nu * FFPOW2(maxLevel() - this->a_level(pCellId)));
1014 }
1015
1016 const MFloat R = a_oldDistribution(pCellId, 26);
1017 const MFloat Nw = a_oldDistribution(pCellId, 7);
1018 const MFloat W = a_oldDistribution(pCellId, 0);
1019 const MFloat Sw = a_oldDistribution(pCellId, 6);
1020 const MFloat S = a_oldDistribution(pCellId, 2);
1021 const MFloat Se = a_oldDistribution(pCellId, 8);
1022 const MFloat E = a_oldDistribution(pCellId, 1);
1023 const MFloat Ne = a_oldDistribution(pCellId, 9);
1024 const MFloat N = a_oldDistribution(pCellId, 3);
1025 const MFloat Nf = a_oldDistribution(pCellId, 17);
1026 const MFloat Nb = a_oldDistribution(pCellId, 16);
1027 const MFloat Sf = a_oldDistribution(pCellId, 15);
1028 const MFloat Sb = a_oldDistribution(pCellId, 14);
1029 const MFloat Ef = a_oldDistribution(pCellId, 13);
1030 const MFloat Eb = a_oldDistribution(pCellId, 12);
1031 const MFloat Wf = a_oldDistribution(pCellId, 11);
1032 const MFloat Wb = a_oldDistribution(pCellId, 10);
1033 const MFloat F = a_oldDistribution(pCellId, 5);
1034 const MFloat B = a_oldDistribution(pCellId, 4);
1035 const MFloat Nwf = a_oldDistribution(pCellId, 21);
1036 const MFloat Nwb = a_oldDistribution(pCellId, 20);
1037 const MFloat Nef = a_oldDistribution(pCellId, 25);
1038 const MFloat Neb = a_oldDistribution(pCellId, 24);
1039 const MFloat Swf = a_oldDistribution(pCellId, 19);
1040 const MFloat Swb = a_oldDistribution(pCellId, 18);
1041 const MFloat Sef = a_oldDistribution(pCellId, 23);
1042 const MFloat Seb = a_oldDistribution(pCellId, 22);
1043
1044 const MFloat rho = Nw + W + Sw + S + Se + E + Ne + N + R + Nf + Nb + Sf + Sb + Ef + Eb + Wf + Wb + Nwf + Nwb + Nef
1045 + Neb + Swf + Swb + Sef + Seb + F + B;
1046 const MFloat pi_x =
1047 (Ne + E + Se + Ef + Eb - Nw - W - Sw - Wf - Wb + Nef + Neb + Sef + Seb - Nwf - Nwb - Swf - Swb);
1048 const MFloat pi_y =
1049 (Ne + N + Nw + Nf + Nb - Se - S - Sw - Sf - Sb + Nef + Neb + Nwf + Nwb - Sef - Seb - Swf - Swb);
1050 const MFloat pi_z =
1051 (Nf + Sf + Wf + Ef + F - Nb - Sb - Wb - Eb - B + Nef + Nwf + Sef + Swf - Neb - Nwb - Seb - Swb);
1052 const MFloat vv_x = pi_x / rho;
1053 const MFloat vv_y = pi_y / rho;
1054 const MFloat vv_z = pi_z / rho;
1055 const MFloat vx2 = vv_x * vv_x;
1056 const MFloat vy2 = vv_y * vv_y;
1057 const MFloat vz2 = vv_z * vv_z;
1058 const MFloat uxy = (m_omega
1059 * (Ne + Neb + Nef - Nw - Nwb - Nwf - Se - Seb - Sef + Sw + Swb + Swf + vv_x * vv_y * rho
1060 - pi_x * vv_y - pi_y * vv_x)
1061 * 0.25);
1062 const MFloat uxz = (m_omega
1063 * (-Eb + Ef - Neb + Nef + Nwb - Nwf - Seb + Sef + Swb - Swf + Wb - Wf + vv_x * vv_z * rho
1064 - pi_x * vv_z - pi_z * vv_x)
1065 * 0.25);
1066 const MFloat uyz = (m_omega
1067 * (-Nb - Neb + Nef + Nf - Nwb + Nwf + Sb + Seb - Sef - Sf + Swb - Swf + vv_z * vv_y * rho
1068 - pi_z * vv_y - pi_y * vv_z)
1069 * 0.25);
1070
1071 const MFloat vxy = (m_omega * (1. / 6.)
1072 * (-B - E - F + Nb + Ne + Nf + Nw + Sb + Se + Sf + Sw - W + 2 * (-Eb - Ef + N + S - Wb - Wf)
1073 + 2 * (-2 * pi_y * vv_y + pi_x * vv_x + pi_z * vv_z) - rho * (vz2 - 2 * vy2 + vx2)));
1074 const MFloat vxz = (m_omega * (1. / 6.)
1075 * (-E + Eb + Ef - N + Nb + Nf - S + Sb + Sf - W + Wb + Wf + 2 * (B + F - Ne - Nw - Se - Sw)
1076 + 2 * (-2 * pi_z * vv_z + pi_x * vv_x + pi_y * vv_y) - rho * (vx2 + vy2 - 2 * vz2)));
1077 const MFloat pe = ((1. / 126.)
1078 * (-B - E - F - N - S - W + 2 * (-Eb - Ef - Nb - Ne - Nf - Nw - Sb - Se - Sf - Sw - Wb - Wf)
1079 + 3 * (-Neb - Nef - Nwb - Nwf - Seb - Sef - Swb - Swf)
1080 + (rho + vv_y * (2 * pi_y - vv_y * rho) + vv_z * (2 * pi_z - vv_z * rho)
1081 + vv_x * (2 * pi_x - vv_x * rho))));
1082
1083 const MFloat UXY = -Ne - Neb - Nef + Nw + Nwb + Nwf + Se + Seb + Sef - Sw - Swb - Swf + 4 * uxy;
1084 const MFloat UXZ = Eb - Ef + Neb - Nef - Nwb + Nwf + Seb - Sef - Swb + Swf - Wb + Wf + 4 * uxz;
1085 const MFloat UYZ = Nb + Neb - Nef - Nf + Nwb - Nwf - Sb - Seb + Sef + Sf - Swb + Swf + 4 * uyz;
1086
1087 const MFloat x =
1088 ((0.125
1089 * (Nw + Sw + Wf + Wb - Eb - Ef - Ne - Se
1090 + vv_x
1091 * (B + Eb + Ef + 84 * pe + F + N + Ne + Nw + S + Se + Sw + Wb + Wf
1092 + 2 * (Nb + Neb + Nef + Nf + Nwb + Nwf + Sb + Seb + Sef + Sf + Swb + Swf - vxy - vxz)))
1093 + 0.25 * (-Neb - Nef + Nwb + Nwf - Seb - Sef + Swb + Swf - vv_y * UXY - vv_z * UXZ)
1094 - 0.25 * vv_x * (vv_y * pi_y + vv_z * pi_z) + 0.125 * (vy2 + vz2) * (vv_x * rho - pi_x)));
1095 const MFloat y =
1096 ((0.125
1097 * (Sb + Sf + Se + Sw - Nw - Ne - Nf - Nb
1098 + vv_y
1099 * (B + E + 84 * pe + F + Nb + Ne + Nf + Nw + Sb + Se + Sf + Sw + W
1100 + 2 * (Eb + Ef + Neb + Nef + Nwb + Nwf + Seb + Sef + Swb + Swf + Wb + Wf + vxy)))
1101 + 0.25 * (-Neb - Nef - Nwb - Nwf + Seb + Sef + Swb + Swf - vv_x * UXY - vv_z * UYZ)
1102 - 0.25 * vv_y * (vv_z * pi_z + vv_x * pi_x) + 0.125 * (vx2 + vz2) * (vv_y * rho - pi_y)));
1103 const MFloat z =
1104 ((0.125
1105 * (Eb + Nb + Sb + Wb - Ef - Nf - Sf - Wf
1106 + vv_z
1107 * (E + Eb + Ef + N + Nb + Nf + S + Sb + Sf + W + Wb + Wf + 84 * pe
1108 + 2 * (Ne + Neb + Nef + Nw + Nwb + Nwf + Se + Seb + Sef + Sw + Swb + Swf + vxz)))
1109 + 0.25 * (-Nef + Neb + Nwb - Nwf + Seb - Sef + Swb - Swf - vv_x * UXZ - vv_y * UYZ)
1110 - 0.25 * vv_z * (vv_x * pi_x + vv_y * pi_y) + 0.125 * (vx2 + vy2) * (vv_z * rho - pi_z)));
1111
1112 const MFloat xxx = ((0.125
1113 * (Eb + Ef - Ne + Nw - Se + Sw - Wb - Wf
1114 + vv_x * (-B - Eb - Ef - F + N + Ne + Nw + S + Se + Sw - Wb - Wf + 2 * (vxz - vxy)))
1115 + 0.25 * (vv_z * UXZ - vv_y * UXY + vv_x * (vv_z * pi_z - vv_y * pi_y))
1116 + 0.125 * ((pi_x - vv_x * rho) * (vz2 - vy2))));
1117 const MFloat yyy =
1118 ((0.125
1119 * (Ne - Nb - Nf + Nw + Sb - Se + Sf - Sw
1120 + vv_y * (-E + B + F + Nb - Ne + Nf - Nw + Sb - Se + Sf - Sw - W + 2 * (-vxy - 2 * vxz)))
1121 + 0.25 * (vv_x * UXY - vv_z * UYZ + vv_y * (vv_x * pi_x - vv_z * pi_z))
1122 + 0.125 * ((pi_y - vv_y * rho) * (vx2 - vz2))));
1123 const MFloat zzz =
1124 ((0.125
1125 * (Eb - Ef - Nb + Nf - Sb + Sf + Wb - Wf
1126 + vv_z * (E + Eb + Ef - N - Nb - Nf - S - Sb - Sf + W + Wb + Wf + 2 * (vxz + 2 * vxy)))
1127 + 0.25 * (vv_y * UYZ - vv_x * UXZ + vv_z * (vv_y * pi_y - vv_x * pi_x))
1128 + 0.125 * ((pi_z - vv_z * rho) * (vy2 - vx2))));
1129
1130 const MFloat xyz =
1131 (0.125
1132 * (Neb - Nef - Nwb + Nwf - Seb + Sef + Swb - Swf - vv_x * UYZ - vv_y * UXZ - vv_z * UXY
1133 + rho * vv_x * vv_y * vv_z - (vv_x * vv_y * pi_z + vv_x * pi_y * vv_z + pi_x * vv_y * vv_z)));
1134
1135 const MFloat X_ =
1136 (Eb + Ef + Ne - Nw + Se - Sw - Wb - Wf + 2 * (Neb + Nef - Nwb - Nwf + Seb + Sef - Swb - Swf) + 8 * x);
1137 const MFloat Y_ =
1138 (Nb + Ne + Nf + Nw - Sb - Se - Sf - Sw + 2 * (Neb + Nef + Nwb + Nwf - Seb - Sef - Swb - Swf) + 8 * y);
1139 const MFloat Z_ =
1140 (Ef - Eb - Nb + Nf - Sb + Sf - Wb + Wf + 2 * (Nef - Neb - Nwb + Nwf - Seb + Sef - Swb + Swf) + 8 * z);
1141
1142 const MFloat XnXXX = Eb + Ef + Neb + Nef - Nwb - Nwf + Seb + Sef - Swb - Swf - Wb - Wf + 4 * (x - xxx);
1143 const MFloat XpXXX = Ne + Neb + Nef - Nw - Nwb - Nwf + Se + Seb + Sef - Sw - Swb - Swf + 4 * (x + xxx);
1144 const MFloat YnYYY = Ne + Neb + Nef + Nw + Nwb + Nwf - Se - Seb - Sef - Sw - Swb - Swf + 4 * (y - yyy);
1145 const MFloat YpYYY = Nb + Neb + Nef + Nf + Nwb + Nwf - Sb - Seb - Sef - Sf - Swb - Swf + 4 * (y + yyy);
1146 const MFloat ZnZZZ = Nef - Nb - Neb + Nf - Nwb + Nwf - Sb - Seb + Sef + Sf - Swb + Swf + 4 * (z - zzz);
1147 const MFloat ZpZZZ = Nef - Eb + Ef - Neb - Nwb + Nwf - Seb + Sef - Swb + Swf - Wb + Wf + 4 * (z + zzz);
1148
1149 const MFloat XYZ = -Neb + Nef + Nwb - Nwf + Seb - Sef - Swb + Swf + 8 * xyz;
1150 const MFloat EPa = -42 * pe - E - Eb - Ef - Ne - Neb - Nef - Nw - Nwb - Nwf - Se - Seb - Sef - Sw - Swb - Swf - W
1151 - Wb - Wf - 2 * (vxy + vxz);
1152 const MFloat EPb = -42 * pe - B - Eb - Ef - F - Nb - Neb - Nef - Nf - Nwb - Nwf - Sb - Seb - Sef - Sf - Swb - Swf
1153 - Wb - Wf + 2 * vxz;
1154 const MFloat EPc = -42 * pe - N - Nb - Ne - Neb - Nef - Nf - Nw - Nwb - Nwf - S - Sb - Se - Seb - Sef - Sf - Sw
1155 - Swb - Swf + 2 * vxy;
1156
1157 const MFloat p =
1158 ((1. / 12.)
1159 * (rho / (3.) - 96 * pe - Eb - Ef - Nb - Ne - Nf - Nw - Sb - Se - Sf - Sw - Wb - Wf
1160 - 3 * (Nwf + Nwb + Nef + Neb + Swf + Swb + Sef + Seb) + 2 * (+vv_x * X_ + vv_y * Y_ + vv_z * Z_)
1161 + vx2
1162 * (-84 * pe - B - Eb - Ef - F - N - Ne - Nw - S - Se - Sw - Wb - Wf
1163 + 2 * (vxy + vxz - Nb - Neb - Nef - Nf - Nwb - Nwf - Sb - Seb - Sef - Sf - Swb - Swf))
1164 + vy2
1165 * (-84 * pe - B - E - F - Nb - Ne - Nf - Nw - Sb - Se - Sf - Sw - W
1166 + 2 * (-vxy - Eb - Ef - Neb - Nef - Nwb - Nwf - Seb - Sef - Swb - Swf - Wb - Wf))
1167 + vz2
1168 * (-84 * pe - E - Eb - Ef - N - Nb - Nf - S - Sb - Sf - W - Wb - Wf
1169 + 2 * (-vxz - Ne - Neb - Nef - Nw - Nwb - Nwf - Se - Seb - Sef - Sw - Swb - Swf))
1170 + 4 * (vv_x * vv_y * UXY + vv_x * vv_z * UXZ + vv_y * vv_z * UYZ)
1171 - rho * (vx2 * vy2 + vx2 * vz2 + vy2 * vz2)
1172 + 2 * (pi_y * vv_y * (vx2 + vz2) + pi_x * vv_x * (vy2 + vz2) + pi_z * vv_z * (vx2 + vy2))));
1173 const MFloat a =
1174 ((1. / 12.)
1175 * (-Eb - Ef - Ne - Nw - Se - Sw - Wb - Wf
1176 + 2
1177 * (Nb + Nf + Sb + Sf + vv_x * X_
1178 + vv_y
1179 * (Ne - Neb - Nef + Nw - Nwb - Nwf - Se + Seb + Sef - Sw + Swb + Swf
1180 + 2 * (Sf + Sb - Nb - Nf - 2 * y - 6 * yyy))
1181 + vv_z
1182 * (Ef - Eb + Neb - Nef + Nwb - Nwf + Seb - Sef + Swb - Swf - Wb + Wf
1183 + 2 * (Nb - Nf + Sb - Sf - 2 * z + 6 * zzz)))
1184 + vx2
1185 * (-B - Eb - Ef - F - N - Ne - Nw - S - Se - Sw - Wb - Wf - 84 * pe
1186 - 2 * (Nb + Neb + Nef + Nf + Nwb + Nwf + Sb + Seb + Sef + Sf + Swb + Swf - vxy - vxz))
1187 + vy2
1188 * (Eb - E + Ef - Ne + Neb + Nef - Nw + Nwb + Nwf - Se + Seb + Sef - Sw + Swb + Swf - W + Wb + Wf
1189 + 42 * pe + 2 * (B + F + Nb + Nf + Sb + Sf - vxy - 3 * vxz))
1190 + vz2
1191 * (Ne - E - Eb - Ef + Neb + Nef + Nw + Nwb + Nwf + Se + Seb + Sef + Sw + Swb + Swf - W - Wb - Wf
1192 + 42 * pe + 2 * (N + Nb + Nf + S + Sb + Sf - vxz - 3 * vxy))
1193 + 4 * (vv_x * (vv_y * UXY + vv_z * UXZ)) - 8 * vv_y * vv_z * UYZ
1194 + (2 * vy2 * vz2 - vx2 * (vy2 + vz2)) * rho
1195 + 2 * (pi_y * vv_y * (vx2 - 2 * vz2) + pi_z * vv_z * (vx2 - 2 * vy2) + pi_x * vv_x * (vy2 + vz2))));
1196 const MFloat c =
1197 ((1. / 12.)
1198 * (-Nb - Ne - Nf - Nw - Sb - Se - Sf - Sw
1199 + 2
1200 * (Eb + Ef + Wb + Wf
1201 + vv_x
1202 * (Ne - Neb - Nef - Nw + Nwb + Nwf + Se - Seb - Sef - Sw + Swb + Swf
1203 + 2 * (Wb + Wf - Eb - Ef - 2 * x + 6 * xxx))
1204 + vv_y * Y_
1205 + vv_z
1206 * (Nf - Nb + Neb - Nef + Nwb - Nwf - Sb + Seb - Sef + Sf + Swb - Swf
1207 + 2 * (Eb - Ef + Wb - Wf - 2 * z - 6 * zzz)))
1208 + vx2
1209 * (Nb - N - Ne + Neb + Nef + Nf - Nw + Nwb + Nwf - S + Sb - Se + Seb + Sef + Sf - Sw + Swb + Swf
1210 + 42 * pe + 2 * (B + Eb + Ef + F + Wb + Wf + vxy - 2 * vxz))
1211 - vy2
1212 * (B + E + F + Nb + Ne + Nf + Nw + Sb + Se + Sf + Sw + W + 84 * pe
1213 + 2 * (Eb + Ef + Neb + Nef + Nwb + Nwf + Seb + Sef + Swb + Swf + Wb + Wf + vxy))
1214 + vz2
1215 * (Ne - N - Nb + Neb + Nef - Nf + Nw + Nwb + Nwf - S - Sb + Se + Seb + Sef - Sf + Sw + Swb + Swf
1216 + 42 * pe + 2 * (E + Eb + Ef + W + Wb + Wf + 3 * vxy + 2 * vxz))
1217 + 4 * vv_y * (vv_x * UXY + vv_z * UYZ) - 8 * vv_x * vv_z * UXZ + (2 * vx2 * vz2 - (vx2 + vz2) * vy2) * rho
1218 + 2 * (pi_x * vv_x * (vy2 - 2 * vz2) + pi_z * vv_z * (vy2 - 2 * vx2) + pi_y * vv_y * (vx2 + vz2))));
1219 const MFloat uxxyz = ((1. / 8.)
1220 * (Neb - Nef + Nwb - Nwf - Seb + Sef - Swb + Swf + vv_y * ZpZZZ + vv_z * YnYYY
1221 + 2 * vv_x * (XYZ + vv_y * UXZ + vv_z * UXY) + vx2 * UYZ + vv_y * vv_z * EPa
1222 + (2 * pi_x - rho * vv_x) * vv_x * vv_y * vv_z + vx2 * (pi_y * vv_z + pi_z * vv_y)));
1223 const MFloat uxyyz = ((1. / 8.)
1224 * (Neb - Nef - Nwb + Nwf + Seb - Sef - Swb + Swf + vv_x * ZnZZZ /*YnYYY*/ + vv_z * XpXXX
1225 + 2 * vv_y * (XYZ + vv_x * UYZ + vv_z * UXY) + vy2 * UXZ
1226 + vv_x * vv_z * EPc
1227 //+rho*3*vy2*vv_x*vv_z
1228 + (2 * pi_y - vv_y * rho) * vv_y * vv_x * vv_z + vy2 * (pi_x * vv_z + pi_z * vv_x)));
1229 const MFloat uxyzz = ((1. / 8.)
1230 * (Nwb - Neb - Nef + Nwf + Seb + Sef - Swb - Swf + vv_x * YpYYY + vv_y * XnXXX
1231 + 2 * vv_z * (XYZ + vv_y * UXZ + vv_x * UYZ) + vz2 * UXY + vv_x * vv_y * EPb
1232 + (2 * pi_z - vv_z * rho) * vv_x * vv_y * vv_z + vz2 * (pi_y * vv_x + pi_x * vv_y)));
1233
1234 const MFloat A = 4 * a - 32 * pe - Nb - Neb - Nef - Nf - Nwb - Nwf - 4 * p - Sb - Seb - Sef - Sf - Swb - Swf;
1235 const MFloat C = 4 * (c - p) - Eb - Ef - 32 * pe - Neb - Nef - Nwb - Nwf - Seb - Sef - Swb - Swf - Wb - Wf;
1236 const MFloat CA = -4 * (a + c + p) - 32 * pe - Ne - Neb - Nef - Nw - Nwb - Nwf - Se - Seb - Sef - Sw - Swb - Swf;
1237 const MFloat UXYZZ = Nwb - Neb - Nef + Nwf + Seb + Sef - Swb - Swf - 8 * uxyzz;
1238 const MFloat UXYYZ = Neb - Nef - Nwb + Nwf + Seb - Sef - Swb + Swf - 8 * uxyyz;
1239 const MFloat UXXYZ = Neb - Nef + Nwb - Nwf - Seb + Sef - Swb + Swf - 8 * uxxyz;
1240
1241 const MFloat xyyzz =
1242 ((1. / 8.)
1243 * (Nwb - Neb - Nef + Nwf - Seb - Sef + Swb + Swf - vv_x * A - 2 * (vv_y * UXYZZ + vv_z * UXYYZ) - vy2 * XnXXX
1244 - vz2 * XpXXX + 2 * vv_x * (-vv_y * YpYYY - vv_z * ZnZZZ) - 4 * vv_y * vv_z * (XYZ + vv_x * UYZ)
1245 - vv_x * (vz2 * EPc + vy2 * EPb)
1246 - 2 * (vy2 * vv_z * UXZ + vv_y * vz2 * UXY)
1247 //-4*vv_x*vy2*vz2*rho
1248 - 2 * vv_x * vv_y * vv_z * (pi_y * vv_z + pi_z * vv_y) + vy2 * vz2 * (vv_x * rho - pi_x)));
1249 const MFloat xxyzz =
1250 ((1. / 8.)
1251 * (Seb - Neb - Nef - Nwb - Nwf + Sef + Swb + Swf - vv_y * C - 2 * (vv_x * UXYZZ + vv_z * UXXYZ) - vx2 * YpYYY
1252 - vz2 * YnYYY + 2 * vv_y * (-vv_x * XnXXX - vv_z * ZpZZZ) - 4 * vv_x * vv_z * (XYZ + vv_y * UXZ)
1253 - vv_y * (vx2 * EPb + vz2 * EPa)
1254 - 2 * (vx2 * vv_z * UYZ + vv_x * vz2 * UXY)
1255 //-4*vv_y*vx2*vz2*rho
1256 - 2 * vv_x * vv_y * vv_z * (pi_x * vv_z + pi_z * vv_x) + vx2 * vz2 * (vv_y * rho - pi_y)));
1257 const MFloat xxyyz =
1258 ((1. / 8.)
1259 * (Neb - Nef + Nwb - Nwf + Seb - Sef + Swb - Swf - vv_z * CA - 2 * (vv_x * UXYYZ + vv_y * UXXYZ)
1260 - vx2 * ZnZZZ - vy2 * ZpZZZ + 2 * vv_z * (-vv_x * XpXXX - vv_y * YnYYY)
1261 - 4 * vv_x * vv_y * (XYZ + vv_z * UXY) - vv_z * (vx2 * EPc + vy2 * EPa)
1262 - 2 * (vx2 * vv_y * UYZ + vv_x * vy2 * UXZ)
1263 //-4*vx2*vy2*vv_z*rho
1264 - 2 * vv_x * vv_y * vv_z * (pi_x * vv_y + pi_y * vv_x) + vx2 * vy2 * (vv_z * rho - pi_z)));
1265
1266 const MFloat xxyyzz =
1267 ((1. / 8.)
1268 * (rho / 27. - Neb - Nef - Nwb - Nwf - Seb - Sef - Swb - Swf
1269 + 2
1270 * (+vv_x * (Neb + Nef - Nwb - Nwf + Seb + Sef - Swb - Swf + 8 * xyyzz)
1271 + vv_y * (Neb + Nef + Nwb + Nwf - Seb - Sef - Swb - Swf + 8 * xxyzz)
1272 + vv_z * (-Neb + Nef - Nwb + Nwf - Seb + Sef - Swb + Swf + 8 * xxyyz))
1273 + vx2 * A + vy2 * C + vz2 * CA + 4 * (vv_x * vv_y * UXYZZ + vv_x * vv_z * UXYYZ + vv_y * vv_z * UXXYZ)
1274 + 2
1275 * (vx2 * vv_y * YpYYY + vx2 * vv_z * ZnZZZ + vy2 * vv_z * ZpZZZ + vv_x * vy2 * XnXXX
1276 + vv_x * vz2 * XpXXX + vz2 * vv_y * YnYYY)
1277 + 8 * vv_x * vv_y * vv_z * XYZ + vx2 * vz2 * EPc + vx2 * vy2 * EPb + vy2 * vz2 * EPa
1278 + 4 * vv_x * vv_y * vv_z * (vv_z * UXY + vv_y * UXZ + vv_x * UYZ)
1279 + 2 * (vx2 * vy2 * vv_z * pi_z + vx2 * vv_y * pi_y * vz2 + vv_x * pi_x * vy2 * vz2)
1280 - rho * vx2 * vy2 * vz2));
1281
1282 a_distribution(pCellId, 26) = R + (12 * p - 30 * pe - 8 * xxyyzz);
1283 a_distribution(pCellId, 7) =
1284 Nw + c + a - xxx - yyy - x + y + uxy + p + 8 * pe + 2 * (-xxyyzz - xxyzz + xyyzz + uxyzz);
1285 a_distribution(pCellId, 0) = W - 2 * a + 4 * x - 11 * pe + vxy + vxz - 4 * p + 4 * (-xyyzz + xxyyzz);
1286 a_distribution(pCellId, 6) =
1287 Sw + a + c - xxx + yyy - x - y - uxy + p + 8 * pe + 2 * (-xxyyzz + xxyzz + xyyzz - uxyzz);
1288 a_distribution(pCellId, 2) = S - 2 * c + 4 * y - 11 * pe - vxy - 4 * p + 4 * (-xxyzz + xxyyzz);
1289 a_distribution(pCellId, 8) =
1290 Se + a + c + xxx + yyy + x - y + uxy + p + 8 * pe + 2 * (-xxyyzz + xxyzz - xyyzz + uxyzz);
1291 a_distribution(pCellId, 1) = E - 2 * a - 4 * x - 11 * pe + vxy + vxz - 4 * p + 4 * (xyyzz + xxyyzz);
1292 a_distribution(pCellId, 9) =
1293 Ne + c + a + x + y + xxx - yyy - uxy + p + 8 * pe + 2 * (-xxyyzz - xxyzz - xyyzz - uxyzz);
1294 a_distribution(pCellId, 3) = N - 2 * c - 4 * y - 11 * pe - vxy - 4 * p + 4 * (xxyzz + xxyyzz); // s_n;
1295 a_distribution(pCellId, 17) =
1296 Nf - a + yyy - zzz + y + z - uyz + p + 8 * pe + 2 * (-xxyyzz - xxyzz - xxyyz - uxxyz);
1297 a_distribution(pCellId, 16) =
1298 Nb - a + yyy + zzz + y - z + uyz + p + 8 * pe + 2 * (-xxyyzz - xxyzz + xxyyz + uxxyz);
1299 a_distribution(pCellId, 15) =
1300 Sf - a - yyy - zzz - y + z + uyz + p + 8 * pe + 2 * (-xxyyzz + xxyzz - xxyyz + uxxyz);
1301 a_distribution(pCellId, 14) =
1302 Sb - a - yyy + zzz - y - z - uyz + p + 8 * pe + 2 * (-xxyyzz + xxyzz + xxyyz - uxxyz);
1303 a_distribution(pCellId, 13) =
1304 Ef - c - xxx + zzz + x + z - uxz + p + 8 * pe + 2 * (-xxyyzz - xyyzz - xxyyz - uxyyz);
1305 a_distribution(pCellId, 12) =
1306 Eb - c - xxx - zzz + x - z + uxz + p + 8 * pe + 2 * (-xxyyzz - xyyzz + xxyyz + uxyyz);
1307 a_distribution(pCellId, 11) =
1308 Wf - c + xxx + zzz - x + z + uxz + p + 8 * pe + 2 * (-xxyyzz + xyyzz - xxyyz + uxyyz);
1309 a_distribution(pCellId, 10) =
1310 Wb - c + xxx - zzz - x - z - uxz + p + 8 * pe + 2 * (-xxyyzz + xyyzz + xxyyz - uxyyz);
1311 a_distribution(pCellId, 5) = F + 2 * a + 2 * c - 4 * z - 11 * pe - vxz - 4 * p + 4 * (xxyyzz + xxyyz);
1312 a_distribution(pCellId, 4) = B + 2 * a + 2 * c + 4 * z - 11 * pe - vxz - 4 * p + 4 * (-xxyyz + xxyyzz);
1313 a_distribution(pCellId, 21) = Nwf - xyz + uxxyz - uxyyz - uxyzz - (-xxyyz + xyyzz - xxyzz) + xxyyzz;
1314 a_distribution(pCellId, 20) = Nwb + xyz - uxxyz + uxyyz - uxyzz - (xxyyz + xyyzz - xxyzz) + xxyyzz;
1315 a_distribution(pCellId, 25) = Nef + xyz + uxxyz + uxyyz + uxyzz - (-xxyyz - xyyzz - xxyzz) + xxyyzz;
1316 a_distribution(pCellId, 24) = Neb - xyz - uxxyz - uxyyz + uxyzz - (xxyyz - xyyzz - xxyzz) + xxyyzz;
1317 a_distribution(pCellId, 19) = Swf + xyz - uxxyz - uxyyz + uxyzz - (-xxyyz + xyyzz + xxyzz) + xxyyzz;
1318 a_distribution(pCellId, 18) = Swb - xyz + uxxyz + uxyyz + uxyzz - (xxyyz + xyyzz + xxyzz) + xxyyzz;
1319 a_distribution(pCellId, 23) = Sef - xyz - uxxyz + uxyyz - uxyzz - (-xxyyz - xyyzz + xxyzz) + xxyyzz;
1320 a_distribution(pCellId, 22) = Seb + xyz + uxxyz - uxyyz - uxyzz - (xxyyz - xyyzz + xxyzz) + xxyyzz;
1321 }
1322 }
1323 if(m_calculateDissipation && globalTimeStep % m_solutionInterval == 0) {
1324 calculateDissipation();
1325 }
1326}
1327
1337template <MInt nDim, MInt nDist, class SysEqn>
1339 clb_collision_step_base<false>();
1340}
1341
1351template <MInt nDim, MInt nDist, class SysEqn>
1353 clb_collision_step_base<true>();
1354}
1355
1365template <MInt nDim, MInt nDist, class SysEqn>
1367 TERMM(1, "Cumulant collision step only available for D3Q27, yet!");
1368}
1369
1370template <>
1372 TRACE();
1373
1374 constexpr MInt nDist = 27;
1375
1376 constexpr MFloat omega2 = F1;
1377 constexpr MFloat omega3 = F1;
1378 constexpr MFloat omega4 = F1;
1379 constexpr MFloat omega5 = F1;
1380 constexpr MFloat omega6 = F1;
1381 constexpr MFloat omega7 = F1;
1382 constexpr MFloat omega8 = F1;
1383 constexpr MFloat omega9 = F1;
1384 constexpr MFloat omega10 = F1;
1385
1386 // Required for ported functions, since GPUs cannot access the global variable globalTimeStep
1387 const MInt gTS = globalTimeStep;
1388 const MInt maxLevel_ = maxLevel();
1389
1390 maia::parallelFor<true>(0, m_currentMaxNoCells, [=](MInt index) {
1391 const MInt pCellId = m_activeCellList[index];
1392 const MInt lvlDiff = maxLevel_ - a_level(pCellId);
1393 if((gTS - 1) % IPOW2(lvlDiff) != 0) return;
1394
1395 const MFloat l_u = a_variable(pCellId, PV->U);
1396 const MFloat l_v = a_variable(pCellId, PV->V);
1397 const MFloat l_w = a_variable(pCellId, PV->W);
1398 const MFloat l_rho = a_variable(pCellId, PV->RHO);
1399
1400 // Calculation of relaxation rate
1401 //-----------------------------------------------------------------------------
1402 const MFloat tau = F1B2 + F1BCSsq * a_nu(pCellId) * FFPOW2(lvlDiff); // tau_0
1403 const MFloat omega1 = 1.0 / tau;
1404
1405 // Calculation of the central moments
1406 //-----------------------------------------------------------------------------
1407 const MFloat F1Brho = F1 / l_rho;
1408 const MFloat u[3] = {l_u, l_v, l_w};
1409 const MFloat uSq[3] = {u[0] * u[0], u[1] * u[1], u[2] * u[2]};
1410
1411 MFloat centralMoments[3][3][3] = {{{F0, F0, F0}, {F0, F0, F0}, {F0, F0, F0}},
1412 {{F0, F0, F0}, {F0, F0, F0}, {F0, F0, F0}},
1413 {{F0, F0, F0}, {F0, F0, F0}, {F0, F0, F0}}};
1414
1415 // info: these loops are consuming (~50%)
1416 for(MInt dist = 0; dist < 27; dist++) {
1417#ifdef WAR_NVHPC_PSTL
1418 const MFloat xDir = (m_idFld[dist][0] - F1) - u[0];
1419 const MFloat yDir = (m_idFld[dist][1] - F1) - u[1];
1420 const MFloat zDir = (m_idFld[dist][2] - F1) - u[2];
1421#else
1422 const MFloat xDir = (Ld::idFld(dist, 0) - F1) - u[0];
1423 const MFloat yDir = (Ld::idFld(dist, 1) - F1) - u[1];
1424 const MFloat zDir = (Ld::idFld(dist, 2) - F1) - u[2];
1425#endif
1426 const MFloat oldDist = a_oldDistribution(pCellId, dist);
1427 const MFloat pow012[3][3] = {{F1, xDir, xDir * xDir}, {F1, yDir, yDir * yDir}, {F1, zDir, zDir * zDir}};
1428
1429 for(MInt i = 0; i < 3; i++) {
1430 for(MInt j = 0; j < 3; j++) {
1431 const MFloat tmp = pow012[0][i] * pow012[1][j] * oldDist;
1432 centralMoments[i][j][0] += pow012[2][0] * tmp;
1433 centralMoments[i][j][1] += pow012[2][1] * tmp;
1434 centralMoments[i][j][2] += pow012[2][2] * tmp;
1435 }
1436 }
1437 }
1438
1439 // Transformation of central moments in cumulants
1440 //-----------------------------------------------------------------------------
1441 MFloat cumulants[3][3][3];
1442
1443 cumulants[0][0][0] = centralMoments[0][0][0];
1444 cumulants[1][0][0] = centralMoments[1][0][0];
1445 cumulants[0][1][0] = centralMoments[0][1][0];
1446 cumulants[0][0][1] = centralMoments[0][0][1];
1447 cumulants[2][0][0] = centralMoments[2][0][0];
1448 cumulants[0][2][0] = centralMoments[0][2][0];
1449 cumulants[0][0][2] = centralMoments[0][0][2];
1450 cumulants[1][1][0] = centralMoments[1][1][0];
1451 cumulants[1][0][1] = centralMoments[1][0][1];
1452 cumulants[0][1][1] = centralMoments[0][1][1];
1453 cumulants[1][2][0] = centralMoments[1][2][0];
1454 cumulants[1][0][2] = centralMoments[1][0][2];
1455 cumulants[0][1][2] = centralMoments[0][1][2];
1456 cumulants[2][0][1] = centralMoments[2][0][1];
1457 cumulants[2][1][0] = centralMoments[2][1][0];
1458 cumulants[0][2][1] = centralMoments[0][2][1];
1459 cumulants[1][1][1] = centralMoments[1][1][1];
1460
1461 cumulants[2][1][1] =
1462 (centralMoments[2][1][1]
1463 - (centralMoments[2][0][0] * centralMoments[0][1][1] + F2 * centralMoments[1][1][0] * centralMoments[1][0][1])
1464 * F1Brho);
1465 cumulants[1][2][1] =
1466 (centralMoments[1][2][1]
1467 - (centralMoments[0][2][0] * centralMoments[1][0][1] + F2 * centralMoments[1][1][0] * centralMoments[0][1][1])
1468 * F1Brho);
1469 cumulants[1][1][2] =
1470 (centralMoments[1][1][2]
1471 - (centralMoments[0][0][2] * centralMoments[1][1][0] + F2 * centralMoments[0][1][1] * centralMoments[1][0][1])
1472 * F1Brho);
1473
1474 cumulants[2][2][0] =
1475 (centralMoments[2][2][0]
1476 - (centralMoments[2][0][0] * centralMoments[0][2][0] + F2 * centralMoments[1][1][0] * centralMoments[1][1][0])
1477 * F1Brho);
1478 cumulants[2][0][2] =
1479 (centralMoments[2][0][2]
1480 - (centralMoments[2][0][0] * centralMoments[0][0][2] + F2 * centralMoments[1][0][1] * centralMoments[1][0][1])
1481 * F1Brho);
1482 cumulants[0][2][2] =
1483 (centralMoments[0][2][2]
1484 - (centralMoments[0][0][2] * centralMoments[0][2][0] + F2 * centralMoments[0][1][1] * centralMoments[0][1][1])
1485 * F1Brho);
1486
1487 cumulants[1][2][2] =
1488 (centralMoments[1][2][2]
1489 - (centralMoments[0][0][2] * centralMoments[1][2][0] + centralMoments[0][2][0] * centralMoments[1][0][2]
1490 + F4 * centralMoments[0][1][1] * centralMoments[1][1][1]
1491 + F2
1492 * (centralMoments[1][0][1] * centralMoments[0][2][1]
1493 + centralMoments[1][1][0] * centralMoments[0][1][2]))
1494 * F1Brho);
1495 cumulants[2][1][2] =
1496 (centralMoments[2][1][2]
1497 - (centralMoments[2][0][0] * centralMoments[0][1][2] + centralMoments[0][0][2] * centralMoments[2][1][0]
1498 + F4 * centralMoments[1][0][1] * centralMoments[1][1][1]
1499 + F2
1500 * (centralMoments[1][1][0] * centralMoments[1][0][2]
1501 + centralMoments[0][1][1] * centralMoments[2][0][1]))
1502 * F1Brho);
1503 cumulants[2][2][1] =
1504 (centralMoments[2][2][1]
1505 - (centralMoments[2][0][0] * centralMoments[0][2][1] + centralMoments[0][2][0] * centralMoments[2][0][1]
1506 + F4 * centralMoments[1][1][0] * centralMoments[1][1][1]
1507 + F2
1508 * (centralMoments[1][0][1] * centralMoments[1][2][0]
1509 + centralMoments[0][1][1] * centralMoments[2][1][0]))
1510 * F1Brho);
1511
1512 const MFloat B0 =
1513 F4 * centralMoments[1][1][1] * centralMoments[1][1][1] + centralMoments[2][0][0] * centralMoments[0][2][2]
1514 + centralMoments[0][2][0] * centralMoments[2][0][2] + centralMoments[0][0][2] * centralMoments[2][2][0];
1515
1516 const MFloat B1 = centralMoments[0][1][1] * centralMoments[2][1][1]
1517 + centralMoments[1][0][1] * centralMoments[1][2][1]
1518 + centralMoments[1][1][0] * centralMoments[1][1][2];
1519
1520 const MFloat B2 = centralMoments[1][2][0] * centralMoments[1][0][2]
1521 + centralMoments[2][1][0] * centralMoments[0][1][2]
1522 + centralMoments[2][0][1] * centralMoments[0][2][1];
1523
1524 const MFloat B3 = centralMoments[1][1][0] * centralMoments[1][0][1] * centralMoments[0][1][1];
1525
1526 const MFloat B4 = centralMoments[1][0][1] * centralMoments[1][0][1] * centralMoments[0][2][0]
1527 + centralMoments[1][1][0] * centralMoments[1][1][0] * centralMoments[0][0][2]
1528 + centralMoments[0][1][1] * centralMoments[0][1][1] * centralMoments[2][0][0];
1529
1530 const MFloat B5 = centralMoments[2][0][0] * centralMoments[0][2][0] * centralMoments[0][0][2];
1531
1532 cumulants[2][2][2] = (centralMoments[2][2][2] - (F1 * B0 + F4 * B1 + F2 * B2) * F1Brho
1533 + (16.0 * B3 + F4 * B4 + F2 * B5) * F1Brho * F1Brho);
1534
1535 // Cumulant collision
1536 //-----------------------------------------------------------------------------
1537 const MFloat sum = cumulants[2][0][0] + cumulants[0][2][0] + cumulants[0][0][2];
1538 const MFloat diff1 = cumulants[2][0][0] - cumulants[0][2][0];
1539 const MFloat diff2 = cumulants[2][0][0] - cumulants[0][0][2];
1540 const MFloat Dxu =
1541 -omega1 * F1Brho * F1B2 * (diff1 + diff2) - omega2 * F1Brho * F1B2 * (sum - centralMoments[0][0][0]);
1542 const MFloat Dyv = Dxu + F3B2 * omega1 * F1Brho * diff1;
1543 const MFloat Dzw = Dxu + F3B2 * omega1 * F1Brho * diff2;
1544 const MFloat A1 = (F1 - omega1) * diff1 - F3 * l_rho * (F1 - F1B2 * omega1) * (uSq[0] * Dxu - uSq[1] * Dyv);
1545 const MFloat A2 = (F1 - omega1) * diff2 - F3 * l_rho * (F1 - F1B2 * omega1) * (uSq[0] * Dxu - uSq[2] * Dzw);
1546 const MFloat A3 = (F1 - omega2) * sum
1547 - F3 * l_rho * (F1 - F1B2 * omega2) * (uSq[0] * Dxu + uSq[1] * Dyv + uSq[2] * Dzw)
1548 + omega2 * centralMoments[0][0][0];
1549
1550 const MFloat A4 = (F1 - omega3) * (cumulants[1][2][0] + cumulants[1][0][2]);
1551 const MFloat A5 = (F1 - omega3) * (cumulants[2][1][0] + cumulants[0][1][2]);
1552 const MFloat A6 = (F1 - omega3) * (cumulants[2][0][1] + cumulants[0][2][1]);
1553 const MFloat A7 = (F1 - omega4) * (cumulants[1][2][0] - cumulants[1][0][2]);
1554 const MFloat A8 = (F1 - omega4) * (cumulants[2][1][0] - cumulants[0][1][2]);
1555 const MFloat A9 = (F1 - omega4) * (cumulants[2][0][1] - cumulants[0][2][1]);
1556
1557 const MFloat A10 = (F1 - omega6) * (cumulants[2][2][0] - F2 * cumulants[2][0][2] + cumulants[0][2][2]);
1558 const MFloat A11 = (F1 - omega6) * (cumulants[2][2][0] + cumulants[2][0][2] - F2 * cumulants[0][2][2]);
1559 const MFloat A12 = (F1 - omega7) * (cumulants[2][2][0] + cumulants[2][0][2] + cumulants[0][2][2]);
1560
1561 cumulants[1][1][0] *= (F1 - omega1);
1562 cumulants[0][1][1] *= (F1 - omega1);
1563 cumulants[1][0][1] *= (F1 - omega1);
1564 cumulants[2][0][0] = (A1 + A2 + A3) * F1B3;
1565 cumulants[0][0][2] = (A1 - F2 * A2 + A3) * F1B3;
1566 cumulants[0][2][0] = (-F2 * A1 + A2 + A3) * F1B3;
1567 cumulants[1][2][0] = (A4 + A5) * F1B2;
1568 cumulants[1][0][2] = (A4 - A5) * F1B2;
1569 cumulants[2][1][0] = (A6 + A7) * F1B2;
1570 cumulants[0][1][2] = (A6 - A7) * F1B2;
1571 cumulants[2][0][1] = (A8 + A9) * F1B2;
1572 cumulants[0][2][1] = (A8 - A9) * F1B2;
1573 cumulants[1][1][1] *= (F1 - omega5);
1574 cumulants[2][2][0] = F1B3 * (A10 + A11 + A12);
1575 cumulants[2][0][2] = F1B3 * (A12 - A10);
1576 cumulants[0][2][2] = F1B3 * (A12 - A11);
1577 cumulants[2][1][1] *= (F1 - omega8);
1578 cumulants[1][2][1] *= (F1 - omega8);
1579 cumulants[1][1][2] *= (F1 - omega8);
1580 cumulants[2][2][1] *= (F1 - omega9);
1581 cumulants[2][1][2] *= (F1 - omega9);
1582 cumulants[1][2][2] *= (F1 - omega9);
1583 cumulants[2][2][2] *= (F1 - omega10);
1584
1585 // Transformation of the cumulants in central moments
1586 //-----------------------------------------------------------------------------
1587 centralMoments[0][0][0] = cumulants[0][0][0];
1588 centralMoments[1][0][0] = -cumulants[1][0][0];
1589 centralMoments[0][1][0] = -cumulants[0][1][0];
1590 centralMoments[0][0][1] = -cumulants[0][0][1];
1591 centralMoments[1][1][0] = cumulants[1][1][0];
1592 centralMoments[1][0][1] = cumulants[1][0][1];
1593 centralMoments[0][1][1] = cumulants[0][1][1];
1594 centralMoments[2][0][0] = cumulants[2][0][0];
1595 centralMoments[0][2][0] = cumulants[0][2][0];
1596 centralMoments[0][0][2] = cumulants[0][0][2];
1597 centralMoments[2][1][0] = cumulants[2][1][0];
1598 centralMoments[2][0][1] = cumulants[2][0][1];
1599 centralMoments[0][2][1] = cumulants[0][2][1];
1600 centralMoments[1][2][0] = cumulants[1][2][0];
1601 centralMoments[1][0][2] = cumulants[1][0][2];
1602 centralMoments[0][1][2] = cumulants[0][1][2];
1603 centralMoments[1][1][1] = cumulants[1][1][1];
1604
1605 centralMoments[2][1][1] =
1606 (cumulants[2][1][1]
1607 + (centralMoments[2][0][0] * centralMoments[0][1][1] + F2 * centralMoments[1][1][0] * centralMoments[1][0][1])
1608 * F1Brho);
1609 centralMoments[1][2][1] =
1610 (cumulants[1][2][1]
1611 + (centralMoments[0][2][0] * centralMoments[1][0][1] + F2 * centralMoments[1][1][0] * centralMoments[0][1][1])
1612 * F1Brho);
1613 centralMoments[1][1][2] =
1614 (cumulants[1][1][2]
1615 + (centralMoments[0][0][2] * centralMoments[1][1][0] + F2 * centralMoments[0][1][1] * centralMoments[1][0][1])
1616 * F1Brho);
1617
1618 centralMoments[2][2][0] =
1619 (cumulants[2][2][0]
1620 + (centralMoments[2][0][0] * centralMoments[0][2][0] + F2 * centralMoments[1][1][0] * centralMoments[1][1][0])
1621 * F1Brho);
1622 centralMoments[2][0][2] =
1623 (cumulants[2][0][2]
1624 + (centralMoments[2][0][0] * centralMoments[0][0][2] + F2 * centralMoments[1][0][1] * centralMoments[1][0][1])
1625 * F1Brho);
1626 centralMoments[0][2][2] =
1627 (cumulants[0][2][2]
1628 + (centralMoments[0][0][2] * centralMoments[0][2][0] + F2 * centralMoments[0][1][1] * centralMoments[0][1][1])
1629 * F1Brho);
1630
1631 centralMoments[1][2][2] =
1632 (cumulants[1][2][2]
1633 + (centralMoments[0][0][2] * centralMoments[1][2][0] + centralMoments[0][2][0] * centralMoments[1][0][2]
1634 + F4 * centralMoments[0][1][1] * centralMoments[1][1][1]
1635 + F2
1636 * (centralMoments[1][0][1] * centralMoments[0][2][1]
1637 + centralMoments[1][1][0] * centralMoments[0][1][2]))
1638 * F1Brho);
1639 centralMoments[2][1][2] =
1640 (cumulants[2][1][2]
1641 + (centralMoments[2][0][0] * centralMoments[0][1][2] + centralMoments[0][0][2] * centralMoments[2][1][0]
1642 + F4 * centralMoments[1][0][1] * centralMoments[1][1][1]
1643 + F2
1644 * (centralMoments[1][1][0] * centralMoments[1][0][2]
1645 + centralMoments[0][1][1] * centralMoments[2][0][1]))
1646 * F1Brho);
1647 centralMoments[2][2][1] =
1648 (cumulants[2][2][1]
1649 + (centralMoments[2][0][0] * centralMoments[0][2][1] + centralMoments[0][2][0] * centralMoments[2][0][1]
1650 + F4 * centralMoments[1][1][0] * centralMoments[1][1][1]
1651 + F2
1652 * (centralMoments[1][0][1] * centralMoments[1][2][0]
1653 + centralMoments[0][1][1] * centralMoments[2][1][0]))
1654 * F1Brho);
1655
1656 const MFloat D0 =
1657 F4 * centralMoments[1][1][1] * centralMoments[1][1][1] + centralMoments[2][0][0] * centralMoments[0][2][2]
1658 + centralMoments[0][2][0] * centralMoments[2][0][2] + centralMoments[0][0][2] * centralMoments[2][2][0];
1659
1660 const MFloat D1 = centralMoments[0][1][1] * centralMoments[2][1][1]
1661 + centralMoments[1][0][1] * centralMoments[1][2][1]
1662 + centralMoments[1][1][0] * centralMoments[1][1][2];
1663
1664 const MFloat D2 = centralMoments[1][2][0] * centralMoments[1][0][2]
1665 + centralMoments[2][1][0] * centralMoments[0][1][2]
1666 + centralMoments[2][0][1] * centralMoments[0][2][1];
1667
1668 const MFloat D3 = centralMoments[1][1][0] * centralMoments[1][0][1] * centralMoments[0][1][1];
1669
1670 const MFloat D4 = centralMoments[1][0][1] * centralMoments[1][0][1] * centralMoments[0][2][0]
1671 + centralMoments[1][1][0] * centralMoments[1][1][0] * centralMoments[0][0][2]
1672 + centralMoments[0][1][1] * centralMoments[0][1][1] * centralMoments[2][0][0];
1673
1674 const MFloat D5 = centralMoments[2][0][0] * centralMoments[0][2][0] * centralMoments[0][0][2];
1675
1676 centralMoments[2][2][2] = (cumulants[2][2][2] + (F1 * D0 + F4 * D1 + F2 * D2) * F1Brho
1677 - (16.0 * D3 + F4 * D4 + F2 * D5) * F1Brho * F1Brho);
1678
1679 const MFloat coeff0[3][3] = {{(uSq[0] - u[0]) * F1B2, u[0] - F1B2, F1B2},
1680 {F1 - uSq[0], -F2 * u[0], -F1},
1681 {(uSq[0] + u[0]) * F1B2, u[0] + F1B2, F1B2}};
1682 const MFloat coeff1[3][3] = {{(uSq[1] - u[1]) * F1B2, u[1] - F1B2, F1B2},
1683 {F1 - uSq[1], -F2 * u[1], -F1},
1684 {(uSq[1] + u[1]) * F1B2, u[1] + F1B2, F1B2}};
1685 const MFloat coeff2[3][3] = {{(uSq[2] - u[2]) * F1B2, u[2] - F1B2, F1B2},
1686 {F1 - uSq[2], -F2 * u[2], -F1},
1687 {(uSq[2] + u[2]) * F1B2, u[2] + F1B2, F1B2}};
1688
1689 // info: this loop is very consuming (~30%)
1690 for(MInt dist = 0; dist < nDist; dist++) {
1691#ifdef WAR_NVHPC_PSTL
1692 const MInt i = m_idFld[dist][0];
1693 const MInt j = m_idFld[dist][1];
1694 const MInt k = m_idFld[dist][2];
1695#else
1696 const MInt i = Ld::idFld(dist, 0);
1697 const MInt j = Ld::idFld(dist, 1);
1698 const MInt k = Ld::idFld(dist, 2);
1699#endif
1700 const MFloat ki_00 = coeff0[i][0] * centralMoments[0][0][0] + coeff0[i][1] * centralMoments[1][0][0]
1701 + coeff0[i][2] * centralMoments[2][0][0];
1702 const MFloat ki_01 = coeff0[i][0] * centralMoments[0][0][1] + coeff0[i][1] * centralMoments[1][0][1]
1703 + coeff0[i][2] * centralMoments[2][0][1];
1704 const MFloat ki_02 = coeff0[i][0] * centralMoments[0][0][2] + coeff0[i][1] * centralMoments[1][0][2]
1705 + coeff0[i][2] * centralMoments[2][0][2];
1706 const MFloat ki_10 = coeff0[i][0] * centralMoments[0][1][0] + coeff0[i][1] * centralMoments[1][1][0]
1707 + coeff0[i][2] * centralMoments[2][1][0];
1708 const MFloat ki_11 = coeff0[i][0] * centralMoments[0][1][1] + coeff0[i][1] * centralMoments[1][1][1]
1709 + coeff0[i][2] * centralMoments[2][1][1];
1710 const MFloat ki_12 = coeff0[i][0] * centralMoments[0][1][2] + coeff0[i][1] * centralMoments[1][1][2]
1711 + coeff0[i][2] * centralMoments[2][1][2];
1712 const MFloat ki_20 = coeff0[i][0] * centralMoments[0][2][0] + coeff0[i][1] * centralMoments[1][2][0]
1713 + coeff0[i][2] * centralMoments[2][2][0];
1714 const MFloat ki_21 = coeff0[i][0] * centralMoments[0][2][1] + coeff0[i][1] * centralMoments[1][2][1]
1715 + coeff0[i][2] * centralMoments[2][2][1];
1716 const MFloat ki_22 = coeff0[i][0] * centralMoments[0][2][2] + coeff0[i][1] * centralMoments[1][2][2]
1717 + coeff0[i][2] * centralMoments[2][2][2];
1718
1719 const MFloat kij_0 = coeff1[j][0] * ki_00 + coeff1[j][1] * ki_10 + coeff1[j][2] * ki_20;
1720 const MFloat kij_1 = coeff1[j][0] * ki_01 + coeff1[j][1] * ki_11 + coeff1[j][2] * ki_21;
1721 const MFloat kij_2 = coeff1[j][0] * ki_02 + coeff1[j][1] * ki_12 + coeff1[j][2] * ki_22;
1722
1723 a_distribution(pCellId, dist) = coeff2[k][0] * kij_0 + coeff2[k][1] * kij_1 + coeff2[k][2] * kij_2;
1724 }
1725 });
1726}
1727
1736template <MInt nDim, MInt nDist, class SysEqn>
1738 TRACE();
1739 const MInt globalTimeStep_ = globalTimeStep;
1740 // loop over all cells
1741 maia::parallelFor<true>(0, m_currentMaxNoCells, [=](MInt i) {
1742 const MInt pCellId = m_activeCellList[i];
1743 const MInt lvlDiff = maxLevel() - this->a_level(pCellId);
1744 if((globalTimeStep_ - 1) % IPOW2(lvlDiff) != 0) return;
1745 // Load macroscopic variables
1746 const MFloat rho = a_variable(pCellId, PV->RHO);
1747 std::array<MFloat, nDim> uu;
1748 for(MInt j = 0; j < nDim; j++) {
1749 uu[j] = a_variable(pCellId, PV->U + j);
1750 }
1751 // Collision
1752 const MFloat omega = 1.0 / (0.5 + F1BCSsq * a_nu(pCellId) * FFPOW2(lvlDiff));
1753 std::array<MFloat, nDist> eqDist;
1754 eqDist = getEqDists(rho, uu.data());
1755 for(MInt j = 0; j < nDist; j++) {
1756 a_distribution(pCellId, j) = a_oldDistribution(pCellId, j) + omega * (eqDist[j] - a_oldDistribution(pCellId, j));
1757 }
1758 });
1759}
1760
1769template <MInt nDim, MInt nDist, class SysEqn>
1771 TRACE();
1772
1773 const MInt pvrho = PV->RHO;
1774
1775 constexpr MInt fldlen = Ld::dxQyFld();
1776
1777 // Update the global Reynolds number if we use the tanh-adaption
1778 if(m_tanhInit && (globalTimeStep > m_initStartTime)) {
1779 const MFloat scale =
1780 0.5 * (m_tanhScaleFactor * tanh((5.0 * (MFloat)(globalTimeStep - m_initStartTime) / (MFloat)m_initTime) - 2.5))
1781 + 0.5;
1782
1783 m_Re = m_initRe + scale * (m_finalRe - m_initRe);
1784
1785 // final timestep reached
1786 if(globalTimeStep == m_initStartTime + m_initTime) {
1787 m_Re = m_finalRe;
1788 m_tanhInit = 0;
1789 }
1790 }
1791
1792 // Update the according nu
1793 m_nu = m_Ma * LBCS / m_Re * m_referenceLength;
1794
1795#ifndef WAR_NVHPC_PSTL
1796 // inner loop references
1797 const MInt* const RESTRICT activeCellList = ALIGNED_I(m_activeCellList);
1798 MFloat* const RESTRICT cnu = ALIGNED_MF(&(a_nu(0)));
1799 const MInt* const RESTRICT clevel = ALIGNED_I(&(this->m_cells.level(0)));
1800 MFloat* const RESTRICT oldDistributions = ALIGNED_MF(&(a_oldDistribution(0, 0)));
1801 MFloat* const RESTRICT distributions = ALIGNED_MF(&(a_distribution(0, 0)));
1802 MFloat* const RESTRICT variables = ALIGNED_MF(&(a_variable(0, 0)));
1803 // members and globals
1804 const MInt maxLevel_ = maxLevel();
1805 // distances
1806 const MInt distNu = &a_nu(1) - &a_nu(0);
1807 const MInt distLevel = &(this->m_cells.level(1)) - &(this->m_cells.level(0));
1808 const MInt distVars = &(a_variable(1, 0)) - &(a_variable(0, 0));
1809#endif
1810 // Required for ported functions, since GPUs cannot access the global variable globalTimeStep
1811 const MInt gTS = globalTimeStep;
1812
1813 // loop over all cells
1814 maia::parallelFor<true>(0, m_currentMaxNoCells, [=](MInt i) {
1815#ifdef WAR_NVHPC_PSTL
1816 const MInt pCellId = m_activeCellList[i];
1817 const MInt index = maxLevel() - this->a_level(pCellId);
1818#else
1819 const MInt pCellId = activeCellList[i];
1820 const MInt index = maxLevel_ - clevel[pCellId * distLevel];
1821#endif
1822
1823 // perform collision on finest level in every timestep,
1824 // on the next coarser level every second timestep, and so on
1825 if((gTS - 1) % IPOW2(index) == 0) {
1826 // save nu for bndcnd and interface interpolation
1827#ifndef WAR_NVHPC_PSTL
1828 cnu[pCellId * distNu] = m_nu;
1829
1830 const MInt distStart = pCellId * nDist;
1831 // varStart = (pCellId * distVars) + (distVarOldVar *
1832 // !((MInt)floor((MFloat)localGlobalTimeStep/fpow2[index]) % 2));
1833 const MInt varStart = pCellId * distVars;
1834
1835 MFloat* const oldDistributionsStart = &oldDistributions[distStart];
1836 MFloat* const distributionsStart = &distributions[distStart];
1837 MFloat* const variablesStart = &variables[varStart];
1838#else
1839 a_nu(pCellId) = m_nu;
1840#endif
1841
1842 const MFloat tmp_FPOW2 = FPOW2(index);
1843 const MFloat tmp_FFPOW2 = FFPOW2(index);
1844 const MFloat l_omega = 2.0 / (1.0 + 6.0 * m_nu * tmp_FFPOW2);
1845
1846 swap_variables(pCellId);
1847
1848 // Reinit macroscopic variables before recalculation
1849 MFloat l_v[nDim] = {0.0};
1850 MFloat l_rho = 0.0;
1851 std::array<MFloat, nDist - 1> externalForcing{};
1852
1853 if(m_particleMomentumCoupling) {
1854 for(MInt dir = 0; dir < nDim; dir++) {
1855 for(MInt mi = 0; mi < fldlen; mi++) {
1856#ifdef WAR_NVHPC_PSTL
1857 externalForcing[m_nFld[dir * fldlen + mi]] +=
1858 m_tp[m_distType[m_nFld[dir * fldlen + mi]]] * -1.0 * a_externalForces(pCellId, dir) * F1BCSsq;
1859 externalForcing[m_pFld[dir * fldlen + mi]] +=
1860 m_tp[m_distType[m_pFld[dir * fldlen + mi]]] * 1.0 * a_externalForces(pCellId, dir) * F1BCSsq;
1861#else
1862 externalForcing.at(Ld::nFld(dir, mi)) +=
1863 Ld::tp(Ld::distType(Ld::nFld(dir, mi))) * -1.0 * a_externalForces(pCellId, dir) * F1BCSsq;
1864 externalForcing.at(Ld::pFld(dir, mi)) +=
1865 Ld::tp(Ld::distType(Ld::pFld(dir, mi))) * 1.0 * a_externalForces(pCellId, dir) * F1BCSsq;
1866#endif
1867 }
1868 }
1869 }
1870#ifdef WAR_NVHPC_PSTL
1871 // Add forcing term and calculate density rho
1872 for(MInt j = 0; j < nDist - 1; j++) {
1873 if(m_particleMomentumCoupling) {
1874 a_oldDistribution(pCellId, j) += tmp_FPOW2 * externalForcing[j];
1875 }
1876 // Add forcing term and calculate density rho
1877 l_rho += a_oldDistribution(pCellId, j);
1878 }
1879 // Do not forget the last distribution
1880 l_rho += a_oldDistribution(pCellId, nDist - 1);
1881#else
1882 // Add forcing term and calculate density rho
1883 for(MInt j = 0; j < nDist - 1; j++) {
1884 if(m_particleMomentumCoupling) {
1885 oldDistributionsStart[j] += tmp_FPOW2 * externalForcing.at(j);
1886 }
1887 // Add forcing term and calculate density rho
1888 l_rho += oldDistributionsStart[j];
1889 }
1890 // Do not forget the last distribution
1891 l_rho += oldDistributionsStart[nDist - 1];
1892#endif
1893
1894
1895 // Calculate macroscopic variables
1896#ifndef WAR_NVHPC_PSTL
1897 if constexpr(nDim == 2) {
1898 // WARNING!!! The velocity should be calculated as in 3d
1899 // However, result is correct
1900 // calculation of u
1901 l_v[0] = oldDistributionsStart[1] + oldDistributionsStart[4] + oldDistributionsStart[5]
1902 - oldDistributionsStart[7] - oldDistributionsStart[6] - oldDistributionsStart[0];
1903 // calculation of v
1904 l_v[1] = oldDistributionsStart[7] + oldDistributionsStart[3] + oldDistributionsStart[4]
1905 - oldDistributionsStart[6] - oldDistributionsStart[2] - oldDistributionsStart[5];
1906 } else {
1907#endif
1908 for(MInt j = 0; j < fldlen; j++) {
1909 for(MInt d = 0; d < nDim; d++) {
1910#ifdef WAR_NVHPC_PSTL
1911 l_v[d] += a_oldDistribution(pCellId, m_pFld[d * fldlen + j]);
1912 l_v[d] -= a_oldDistribution(pCellId, m_nFld[d * fldlen + j]);
1913#else
1914 l_v[d] += oldDistributionsStart[Ld::pFld(d, j)];
1915 l_v[d] -= oldDistributionsStart[Ld::nFld(d, j)];
1916#endif
1917 }
1918 }
1919#ifndef WAR_NVHPC_PSTL
1920 }
1921#endif
1922
1923 // Save new macroscopic variables in cell
1924#ifdef WAR_NVHPC_PSTL
1925 for(MInt d = 0; d < nDim; d++) {
1926 a_variable(pCellId, d) = l_v[d];
1927 }
1928 a_variable(pCellId, nDim) = l_rho;
1929#else
1930 for(MInt d = 0; d < nDim; d++) {
1931 variablesStart[d] = l_v[d];
1932 }
1933 variablesStart[pvrho] = l_rho;
1934#endif
1935
1936 const MFloat sqVel = std::inner_product(&l_v[0], &l_v[nDim], &l_v[0], F0);
1937
1938 std::array<MFloat, nDist> eqDist;
1939 eqDist = getEqDists(l_rho, sqVel, l_v);
1940
1941 // Calculation of new distributions
1942#ifdef WAR_NVHPC_PSTL
1943 for(MInt j = 0; j < nDist; j++) {
1944 a_distribution(pCellId, j) =
1945 a_oldDistribution(pCellId, j) + l_omega * (eqDist[j] - a_oldDistribution(pCellId, j));
1946 }
1947#else
1948 for(MInt j = 0; j < nDist; j++) {
1949 distributionsStart[j] = oldDistributionsStart[j] + l_omega * (eqDist[j] - oldDistributionsStart[j]);
1950 }
1951#endif
1952 }
1953 });
1954}
1955
1967template <MInt nDim, MInt nDist, class SysEqn>
1969 TRACE();
1970
1971 if(!m_particleMomentumCoupling)
1972 std::cerr << "Momentum Coupling is not activated, use MAIA_LATTIC_BGK instead!" << std::endl;
1973
1974 const MInt pvrho = PV->RHO;
1975
1976 constexpr MInt fldlen = Ld::dxQyFld();
1977
1978 // Update the global Reynolds number if we use the tanh-adaption
1979 if(m_tanhInit && (globalTimeStep > m_initStartTime)) {
1980 const MFloat scale =
1981 0.5 * (m_tanhScaleFactor * tanh((5.0 * (MFloat)(globalTimeStep - m_initStartTime) / (MFloat)m_initTime) - 2.5))
1982 + 0.5;
1983
1984 m_Re = m_initRe + scale * (m_finalRe - m_initRe);
1985
1986 // final timestep reached
1987 if(globalTimeStep == m_initStartTime + m_initTime) {
1988 m_Re = m_finalRe;
1989 m_tanhInit = 0;
1990 }
1991 }
1992
1993 // Update the according nu
1994 m_nu = m_Ma * LBCS / m_Re * m_referenceLength;
1995
1996 // inner loop references
1997 const MInt* const RESTRICT activeCellList = ALIGNED_I(m_activeCellList);
1998 MFloat* const RESTRICT cnu = ALIGNED_MF(&(a_nu(0)));
1999 const MInt* const RESTRICT clevel = ALIGNED_I(&(this->m_cells.level(0)));
2000 MFloat* const RESTRICT oldDistributions = ALIGNED_MF(&(a_oldDistribution(0, 0)));
2001 MFloat* const RESTRICT distributions = ALIGNED_MF(&(a_distribution(0, 0)));
2002 MFloat* const RESTRICT variables = ALIGNED_MF(&(a_variable(0, 0)));
2003
2004 // members and globals
2005 const MFloat nu = m_nu;
2006
2007 // Required for ported functions, since GPUs cannot access the global variable globalTimeStep
2008 const MInt gTS = globalTimeStep;
2009 const MInt maxLevel_ = maxLevel();
2010
2011 // distances
2012 const MInt distNu = &a_nu(1) - &a_nu(0);
2013 const MInt distLevel = &(this->m_cells.level(1)) - &(this->m_cells.level(0));
2014 const MInt distVars = &(a_variable(1, 0)) - &(a_variable(0, 0));
2015
2016 // loop over all cells
2017 maia::parallelFor<false>(0, m_currentMaxNoCells, [=](MInt i) {
2018 const MInt pCellId = activeCellList[i];
2019 const MInt index = maxLevel_ - clevel[pCellId * distLevel];
2020
2021 // perform collision on finest level in every timestep,
2022 // on the next coarser level every second timestep, and so on
2023 if((gTS - 1) % IPOW2(index) == 0) {
2024 // save nu for bndcnd and interface interpolation
2025 cnu[pCellId * distNu] = nu;
2026
2027 const MInt distStart = pCellId * nDist;
2028 // varStart = (pCellId * distVars) + (distVarOldVar *
2029 // !((MInt)floor((MFloat)localGlobalTimeStep/fpow2[index]) % 2));
2030 const MInt varStart = pCellId * distVars;
2031
2032 MFloat* const oldDistributionsStart = &oldDistributions[distStart];
2033 MFloat* const distributionsStart = &distributions[distStart];
2034
2035 MFloat* const variablesStart = &variables[varStart];
2036
2037 const MFloat tmp_FPOW2 = FPOW2(index);
2038 const MFloat tmp_FFPOW2 = FFPOW2(index);
2039 const MFloat l_omega = 2.0 / (1.0 + 6.0 * nu * tmp_FFPOW2);
2040
2041 swap_variables(pCellId);
2042
2043 // Reinit macroscopic variables before recalculation
2044 MFloat l_v[nDim] = {0.0};
2045 MFloat l_rho = 0.0;
2046 std::array<MFloat, nDist> externalForcing{0.0};
2047
2048 // calculate density rho and velocity
2049 for(MInt j = 0; j < nDist - 1; j++) {
2050 // Add forcing term and calculate density rho
2051 l_rho += oldDistributionsStart[j];
2052 }
2053 // Do not forget the last distribution
2054 l_rho += oldDistributionsStart[nDist - 1];
2055
2056 for(MInt j = 0; j < fldlen; j++) {
2057 for(MInt d = 0; d < nDim; d++) {
2058 l_v[d] += oldDistributionsStart[Ld::pFld(d, j)];
2059 l_v[d] -= oldDistributionsStart[Ld::nFld(d, j)];
2060 }
2061 }
2062
2063 // add forcing term to velocity
2064 for(MInt d = 0; d < nDim; d++) {
2065 l_v[d] += tmp_FPOW2 * F1B2 * a_externalForces(pCellId, d);
2066 }
2067
2068 // Save new macroscopic variables in cell
2069 for(MInt d = 0; d < nDim; d++) {
2070 variablesStart[d] = l_v[d];
2071 }
2072 variablesStart[pvrho] = l_rho;
2073
2074 const MFloat sqVel = std::inner_product(&l_v[0], &l_v[nDim], &l_v[0], F0);
2075
2076 // Compute Sourceterm:
2077 for(MInt j = 0; j < nDist - 1; j++) {
2078 // precompute
2079 std::array<MFloat, nDim> velDiff{};
2080 MFloat scalarProductVel{};
2081 for(MInt dir = 0; dir < nDim; dir++) {
2082 velDiff.at(dir) = Ld::ppdfDir(j, dir) - l_v[dir];
2083 scalarProductVel += Ld::ppdfDir(j, dir) * l_v[dir];
2084 }
2085 for(MInt dir = 0; dir < nDim; dir++) {
2086 externalForcing.at(j) +=
2087 tmp_FPOW2 * (F1 - F1B2 * l_omega) * Ld::tp(Ld::distType(j))
2088 * (F1BCSsq * velDiff.at(dir) + POW2(F1BCSsq) * scalarProductVel * Ld::ppdfDir(j, dir))
2089 * a_externalForces(pCellId, dir);
2090 }
2091 }
2092
2093 std::array<MFloat, nDist> eqDist;
2094 eqDist = getEqDists(l_rho, sqVel, l_v);
2095
2096 // Calculation of new distributions
2097 for(MInt j = 0; j < nDist; j++) {
2098 distributionsStart[j] =
2099 oldDistributionsStart[j] + l_omega * (eqDist[j] - oldDistributionsStart[j]) + externalForcing.at(j);
2100 }
2101 }
2102 });
2103}
2104
2110template <MInt nDim, MInt nDist, class SysEqn>
2112 TRACE();
2113
2114 const MInt pvrho = PV->RHO;
2115 const MInt pvc = PV->C;
2116
2117 constexpr MInt fldlen = Ld::dxQyFld();
2118
2119 // Update the global Reynolds number if we use the tanh-adaption
2120 if(m_tanhInit && (globalTimeStep > m_initStartTime)) {
2121 const MFloat scale =
2122 0.5 * (m_tanhScaleFactor * tanh((5.0 * (MFloat)(globalTimeStep - m_initStartTime) / (MFloat)m_initTime) - 2.5))
2123 + 0.5;
2124
2125 m_Re = m_initRe + scale * (m_finalRe - m_initRe);
2126
2127 // final timestep reached
2128 if(globalTimeStep == m_initStartTime + m_initTime) {
2129 m_Re = m_finalRe;
2130 m_tanhInit = 0;
2131 }
2132 }
2133
2134 // Update the according nu
2135 m_nu = m_Ma * LBCS / m_Re * m_referenceLength;
2136
2137 // Calculate heat diffusion coefficient
2138 m_diffusivity = m_nu * (m_Re / m_Pe);
2139
2140#ifndef WAR_NVHPC_PSTL
2141 // inner loop references
2142 const MInt* const RESTRICT activeCellList = ALIGNED_I(m_activeCellList);
2143 MFloat* const RESTRICT cnu = ALIGNED_MF(&(a_nu(0)));
2144 MFloat* const RESTRICT cdiffusivity = ALIGNED_MF(&(a_diffusivity(0)));
2145 const MInt* const RESTRICT clevel = ALIGNED_I(&(this->m_cells.level(0)));
2146 MFloat* const RESTRICT oldDistributions = ALIGNED_MF(&(a_oldDistribution(0, 0)));
2147 MFloat* const RESTRICT distributions = ALIGNED_MF(&(a_distribution(0, 0)));
2148 MFloat* const RESTRICT oldDistributionsTransport = ALIGNED_MF(&(a_oldDistributionTransport(0, 0)));
2149 MFloat* const RESTRICT distributionsTransport = ALIGNED_MF(&(a_distributionTransport(0, 0)));
2150 MFloat* const RESTRICT variables = ALIGNED_MF(&(a_variable(0, 0)));
2151
2152 // members and globals
2153 const MInt maxLevel_ = maxLevel();
2154 // distances
2155 const MInt distNu = &a_nu(1) - &a_nu(0);
2156 const MInt distDiffusivity = &a_diffusivity(1) - &a_diffusivity(0);
2157 const MInt distLevel = &(this->m_cells.level(1)) - &(this->m_cells.level(0));
2158 const MInt distVars = &(a_variable(1, 0)) - &(a_variable(0, 0));
2159#endif
2160 // Required for ported functions, since GPUs cannot access the global variable globalTimeStep
2161 const MInt gTS = globalTimeStep;
2162
2163 // loop over all cells
2164 maia::parallelFor<true>(0, m_currentMaxNoCells, [=](MInt i) {
2165#ifdef WAR_NVHPC_PSTL
2166 const MInt pCellId = m_activeCellList[i];
2167 const MInt index = maxLevel() - this->a_level(pCellId);
2168#else
2169 const MInt pCellId = activeCellList[i];
2170 const MInt index = maxLevel_ - clevel[pCellId * distLevel];
2171#endif
2172
2173 // perform collision on finest level in every timestep,
2174 // on the next coarser level every second timestep, and so on
2175 if((gTS - 1) % IPOW2(index) == 0) {
2176 // save nu for bndcnd and interface interpolation
2177#ifndef WAR_NVHPC_PSTL
2178 cnu[pCellId * distNu] = m_nu;
2179 cdiffusivity[pCellId * distDiffusivity] = m_diffusivity;
2180
2181 const MInt distStart = pCellId * nDist;
2182 // varStart = (pCellId * distVars) + (distVarOldVar *
2183 // !((MInt)floor((MFloat)localGlobalTimeStep/fpow2[index]) % 2));
2184 const MInt varStart = pCellId * distVars;
2185
2186 MFloat* const oldDistributionsStart = &oldDistributions[distStart];
2187 MFloat* const distributionsStart = &distributions[distStart];
2188 MFloat* const oldDistributionsTransportStart = &oldDistributionsTransport[distStart];
2189 MFloat* const distributionsTransportStart = &distributionsTransport[distStart];
2190
2191 MFloat* const variablesStart = &variables[varStart];
2192#else
2193 a_nu(pCellId) = m_nu;
2194 a_kappa(pCellId) = m_kappa;
2195#endif
2196
2197 const MFloat tmp_FFPOW2 = FFPOW2(index);
2198 const MFloat l_omega = 2.0 / (1.0 + 6.0 * m_nu * tmp_FFPOW2);
2199 const MFloat l_omegaD = 2.0 / (1.0 + 6.0 * m_diffusivity * tmp_FFPOW2);
2200
2201 swap_variables(pCellId);
2202
2203 // Reinit macroscopic variables before recalculation
2204 MFloat l_v[nDim] = {0.0};
2205 MFloat l_rho = 0.0;
2206 MFloat l_c = 0.0;
2207
2208#ifdef WAR_NVHPC_PSTL
2209 // Add forcing term and calculate density rho
2210 for(MInt j = 0; j < nDist - 1; j++) {
2211 // Add forcing term and calculate density rho
2212 l_rho += a_oldDistribution(pCellId, j);
2213 l_c += a_oldDistributionTransport(pCellId, j);
2214 }
2215 // Do not forget the last distribution
2216 l_rho += a_oldDistribution(pCellId, nDist - 1);
2217 l_c += a_oldDistributionTransport(pCellId, nDist - 1);
2218#else
2219 // Add forcing term and calculate density rho
2220 for(MInt j = 0; j < nDist - 1; j++) {
2221 l_rho += oldDistributionsStart[j];
2222 l_c += oldDistributionsTransportStart[j];
2223 }
2224 // Do not forget the last distribution
2225 l_rho += oldDistributionsStart[nDist - 1];
2226 l_c += oldDistributionsTransportStart[nDist - 1];
2227#endif
2228
2229 // Calculate macroscopic variables
2230#ifndef WAR_NVHPC_PSTL
2231 if constexpr(nDim == 2) {
2232 // WARNING!!! The velocity should be calculated as in 3d
2233 // However, result is correct
2234 // calculation of u
2235 l_v[0] = oldDistributionsStart[1] + oldDistributionsStart[4] + oldDistributionsStart[5]
2236 - oldDistributionsStart[7] - oldDistributionsStart[6] - oldDistributionsStart[0];
2237 // calculation of v
2238 l_v[1] = oldDistributionsStart[7] + oldDistributionsStart[3] + oldDistributionsStart[4]
2239 - oldDistributionsStart[6] - oldDistributionsStart[2] - oldDistributionsStart[5];
2240 } else {
2241#endif
2242 for(MInt j = 0; j < fldlen; j++) {
2243 for(MInt d = 0; d < nDim; d++) {
2244#ifdef WAR_NVHPC_PSTL
2245 l_v[d] += a_oldDistribution(pCellId, m_pFld[d * fldlen + j]);
2246 l_v[d] -= a_oldDistribution(pCellId, m_nFld[d * fldlen + j]);
2247#else
2248 l_v[d] += oldDistributionsStart[Ld::pFld(d, j)];
2249 l_v[d] -= oldDistributionsStart[Ld::nFld(d, j)];
2250#endif
2251 }
2252 }
2253#ifndef WAR_NVHPC_PSTL
2254 }
2255#endif
2256
2257 // Save new macroscopic variables in cell
2258#ifdef WAR_NVHPC_PSTL
2259 for(MInt d = 0; d < nDim; d++) {
2260 a_variable(pCellId, d) = l_v[d];
2261 }
2262 a_variable(pCellId, pvrho) = l_rho;
2263 a_variable(pCellId, pvc) = l_c;
2264#else
2265 for(MInt d = 0; d < nDim; d++) {
2266 variablesStart[d] = l_v[d];
2267 }
2268 variablesStart[pvrho] = l_rho;
2269 variablesStart[pvc] = l_c;
2270#endif
2271
2272 MFloat u[nDim] = {0.0};
2273 for(MInt d = 0; d < nDim; d++) {
2274 u[d] = l_v[d] / l_rho;
2275 }
2276
2277 std::array<MFloat, nDist> eqDist;
2278 eqDist = getEqDists(l_rho, u);
2279 std::array<MFloat, nDist> eqDistC;
2280 eqDistC = getEqDistsTransport(l_c, u);
2281
2282 // Calculation of new distributions
2283 for(MInt j = 0; j < nDist; j++) {
2284#ifdef WAR_NVHPC_PSTL
2285 a_distribution(pCellId, j) =
2286 a_oldDistribution(pCellId, j) + l_omega * (eqDist[j] - a_oldDistribution(pCellId, j));
2287 a_distributionTransport(pCellId, j) =
2288 a_oldDistributionTransport(pCellId, j) + l_omegaD * (eqDistC[j] - a_oldDistributionTransport(pCellId, j));
2289#else
2290 distributionsStart[j] = oldDistributionsStart[j] + l_omega * (eqDist[j] - oldDistributionsStart[j]);
2291 distributionsTransportStart[j] = oldDistributionsTransportStart[j] + l_omegaD * (eqDistC[j] - oldDistributionsTransportStart[j]);
2292#endif
2293 }
2294 }
2295 });
2296}
2297
2303template <MInt nDim, MInt nDist, class SysEqn>
2304template <MInt thermalMode>
2306 TRACE();
2307
2308 const MInt pvrho = PV->RHO;
2309 const MInt pvt = PV->T;
2310 const MInt pvc = PV->C;
2311
2312 constexpr MInt fldlen = Ld::dxQyFld();
2313
2314 // Update the global Reynolds number if we use the tanh-adaption
2315 if(m_tanhInit && (globalTimeStep > m_initStartTime)) {
2316 const MFloat scale =
2317 0.5 * (m_tanhScaleFactor * tanh((5.0 * (MFloat)(globalTimeStep - m_initStartTime) / (MFloat)m_initTime) - 2.5))
2318 + 0.5;
2319
2320 m_Re = m_initRe + scale * (m_finalRe - m_initRe);
2321
2322 // final timestep reached
2323 if(globalTimeStep == m_initStartTime + m_initTime) {
2324 m_Re = m_finalRe;
2325 m_tanhInit = 0;
2326 }
2327 }
2328
2329 // Update the according nu
2330 m_nu = m_Ma * LBCS / m_Re * m_referenceLength;
2331
2332 // Calculate heat diffusion coefficient
2333 m_kappa = m_nu / m_Pr;
2334 m_diffusivity = m_nu * (m_Re / m_Pe);
2335
2336#ifndef WAR_NVHPC_PSTL
2337 // inner loop references
2338 const MInt* const RESTRICT activeCellList = ALIGNED_I(m_activeCellList);
2339 MFloat* const RESTRICT cnu = ALIGNED_MF(&(a_nu(0)));
2340 MFloat* const RESTRICT ckappa = ALIGNED_MF(&(a_kappa(0)));
2341 MFloat* const RESTRICT cdiffusivity = ALIGNED_MF(&(a_diffusivity(0)));
2342 const MInt* const RESTRICT clevel = ALIGNED_I(&(this->m_cells.level(0)));
2343 MFloat* const RESTRICT oldDistributions = ALIGNED_MF(&(a_oldDistribution(0, 0)));
2344 MFloat* const RESTRICT distributions = ALIGNED_MF(&(a_distribution(0, 0)));
2345 MFloat* const RESTRICT oldDistributionsThermal = ALIGNED_MF(&(a_oldDistributionThermal(0, 0)));
2346 MFloat* const RESTRICT distributionsThermal = ALIGNED_MF(&(a_distributionThermal(0, 0)));
2347 MFloat* const RESTRICT oldDistributionsTransport = ALIGNED_MF(&(a_oldDistributionTransport(0, 0)));
2348 MFloat* const RESTRICT distributionsTransport = ALIGNED_MF(&(a_distributionTransport(0, 0)));
2349 MFloat* const RESTRICT variables = ALIGNED_MF(&(a_variable(0, 0)));
2350
2351 // members and globals
2352 const MInt maxLevel_ = maxLevel();
2353 // distances
2354 const MInt distNu = &a_nu(1) - &a_nu(0);
2355 const MInt distKappa = &a_kappa(1) - &a_kappa(0);
2356 const MInt distDiffusivity = &a_diffusivity(1) - &a_diffusivity(0);
2357 const MInt distLevel = &(this->m_cells.level(1)) - &(this->m_cells.level(0));
2358 const MInt distVars = &(a_variable(1, 0)) - &(a_variable(0, 0));
2359#endif
2360 // Required for ported functions, since GPUs cannot access the global variable globalTimeStep
2361 const MInt gTS = globalTimeStep;
2362
2363 const MFloat factor = (thermalMode == 1) ? ((nDim == 2) ? 3.0 : 18.0 / 5.0) : F6;
2364
2365 // loop over all cells
2366 maia::parallelFor<true>(0, m_currentMaxNoCells, [=](MInt i) {
2367#ifdef WAR_NVHPC_PSTL
2368 const MInt pCellId = m_activeCellList[i];
2369 const MInt index = maxLevel() - this->a_level(pCellId);
2370#else
2371 const MInt pCellId = activeCellList[i];
2372 const MInt index = maxLevel_ - clevel[pCellId * distLevel];
2373#endif
2374
2375 // perform collision on finest level in every timestep,
2376 // on the next coarser level every second timestep, and so on
2377 if((gTS - 1) % IPOW2(index) == 0) {
2378 // save nu for bndcnd and interface interpolation
2379#ifndef WAR_NVHPC_PSTL
2380 cnu[pCellId * distNu] = m_nu;
2381 ckappa[pCellId * distKappa] = m_kappa;
2382 cdiffusivity[pCellId * distDiffusivity] = m_diffusivity;
2383
2384 const MInt distStart = pCellId * nDist;
2385 // varStart = (pCellId * distVars) + (distVarOldVar *
2386 // !((MInt)floor((MFloat)localGlobalTimeStep/fpow2[index]) % 2));
2387 const MInt varStart = pCellId * distVars;
2388
2389 MFloat* const oldDistributionsStart = &oldDistributions[distStart];
2390 MFloat* const distributionsStart = &distributions[distStart];
2391 MFloat* const oldDistributionsTStart = &oldDistributionsThermal[distStart];
2392 MFloat* const distributionsTStart = &distributionsThermal[distStart];
2393 MFloat* const oldDistributionsTransportStart = &oldDistributionsTransport[distStart];
2394 MFloat* const distributionsTransportStart = &distributionsTransport[distStart];
2395
2396 MFloat* const variablesStart = &variables[varStart];
2397#else
2398 a_nu(pCellId) = m_nu;
2399 a_kappa(pCellId) = m_kappa;
2400 a_diffusivity(pCellId) = m_diffusivity;
2401#endif
2402
2403 const MFloat tmp_FFPOW2 = FFPOW2(index);
2404 const MFloat l_omega = 2.0 / (1.0 + 6.0 * m_nu * tmp_FFPOW2);
2405 const MFloat l_omegaT = 2.0 / (1.0 + factor * m_kappa * tmp_FFPOW2);
2406 const MFloat l_omegaD = 2.0 / (1.0 + 6.0 * m_diffusivity * tmp_FFPOW2);
2407
2408 swap_variables(pCellId);
2409
2410 // Reinit macroscopic variables before recalculation
2411 MFloat l_v[nDim] = {0.0};
2412 MFloat l_rho = 0.0;
2413 MFloat l_t = 0.0;
2414 MFloat l_c = 0.0;
2415
2416#ifdef WAR_NVHPC_PSTL
2417 // Add forcing term and calculate density rho
2418 for(MInt j = 0; j < nDist - 1; j++) {
2419 // Add forcing term and calculate density rho
2420 l_rho += a_oldDistribution(pCellId, j);
2421 l_t += a_oldDistributionThermal(pCellId, j);
2422 l_c += a_oldDistributionTransport(pCellId, j);
2423 }
2424 // Do not forget the last distribution
2425 l_rho += a_oldDistribution(pCellId, nDist - 1);
2426 l_t += a_oldDistributionThermal(pCellId, nDist - 1);
2427 l_c += a_oldDistributionTransport(pCellId, nDist - 1);
2428#else
2429 // Add forcing term and calculate density rho
2430 for(MInt j = 0; j < nDist - 1; j++) {
2431 l_rho += oldDistributionsStart[j];
2432 l_t += oldDistributionsTStart[j];
2433 l_c += oldDistributionsTransportStart[j];
2434 }
2435 // Do not forget the last distribution
2436 l_rho += oldDistributionsStart[nDist - 1];
2437 l_t += oldDistributionsTStart[nDist - 1];
2438 l_c += oldDistributionsTransportStart[nDist - 1];
2439#endif
2440
2441 // Calculate macroscopic variables
2442#ifndef WAR_NVHPC_PSTL
2443 if constexpr(nDim == 2) {
2444 // WARNING!!! The velocity should be calculated as in 3d
2445 // However, result is correct
2446 // calculation of u
2447 l_v[0] = oldDistributionsStart[1] + oldDistributionsStart[4] + oldDistributionsStart[5]
2448 - oldDistributionsStart[7] - oldDistributionsStart[6] - oldDistributionsStart[0];
2449 // calculation of v
2450 l_v[1] = oldDistributionsStart[7] + oldDistributionsStart[3] + oldDistributionsStart[4]
2451 - oldDistributionsStart[6] - oldDistributionsStart[2] - oldDistributionsStart[5];
2452 } else {
2453#endif
2454 for(MInt j = 0; j < fldlen; j++) {
2455 for(MInt d = 0; d < nDim; d++) {
2456#ifdef WAR_NVHPC_PSTL
2457 l_v[d] += a_oldDistribution(pCellId, m_pFld[d * fldlen + j]);
2458 l_v[d] -= a_oldDistribution(pCellId, m_nFld[d * fldlen + j]);
2459#else
2460 l_v[d] += oldDistributionsStart[Ld::pFld(d, j)];
2461 l_v[d] -= oldDistributionsStart[Ld::nFld(d, j)];
2462#endif
2463 }
2464 }
2465#ifndef WAR_NVHPC_PSTL
2466 }
2467#endif
2468
2469 std::array<MFloat, nDim> u{};
2470 for(MInt d = 0; d < nDim; d++) {
2471 u[d] = l_v[d] / l_rho;
2472 }
2473
2474 // Save new macroscopic variables in cell
2475#ifdef WAR_NVHPC_PSTL
2476 for(MInt d = 0; d < nDim; d++) {
2477 a_variable(pCellId, d) = l_v[d];
2478 }
2479 a_variable(pCellId, pvrho) = l_rho;
2480 a_variable(pCellId, pvc) = l_c;
2481 IF_CONSTEXPR(thermalMode == 0) { a_variable(pCellId, pvt) = l_t; }
2482 IF_CONSTEXPR(thermalMode == 1) {
2483 const MFloat D = (MFloat)nDim;
2484 const MFloat l_ie_rho = l_t;
2485 l_t = l_ie_rho * F2 / (D * l_rho);
2486 a_variable(pCellId, pvt) = l_t;
2487 }
2488 IF_CONSTEXPR(thermalMode == 2) {
2489 const MFloat D = (MFloat)nDim;
2490 const MFloat sqVel = std::inner_product(&u[0], &u[nDim], &u[0], F0);
2491 const MFloat l_te_rho = l_t;
2492 l_t = (l_te_rho / l_rho - sqVel * F1B2) * F2 / D;
2493 a_variable(pCellId, pvt) = l_t;
2494 for(MInt d = 0; d < nDim; d++) {
2495 a_variable(pCellId, d) = l_v[d];
2496 }
2497 }
2498#else
2499 for(MInt d = 0; d < nDim; d++) {
2500 variablesStart[d] = l_v[d];
2501 }
2502 variablesStart[pvrho] = l_rho;
2503 variablesStart[pvc] = l_c;
2504 IF_CONSTEXPR(thermalMode == 0) { variablesStart[pvt] = l_t; }
2505 IF_CONSTEXPR(thermalMode == 1) {
2506 const MFloat D = (MFloat)nDim;
2507 const MFloat l_ie_rho = l_t;
2508 l_t = l_ie_rho * F2 / (D * l_rho);
2509 variablesStart[pvt] = l_t;
2510 }
2511 IF_CONSTEXPR(thermalMode == 2) {
2512 const MFloat D = (MFloat)nDim;
2513 const MFloat sqVel = std::inner_product(&u[0], &u[nDim], &u[0], F0);
2514 const MFloat l_te_rho = l_t;
2515 l_t = (l_te_rho / l_rho - sqVel * F1B2) * F2 / D;
2516 variablesStart[pvt] = l_t;
2517 for(MInt d = 0; d < nDim; d++) {
2518 variablesStart[d] = l_v[d];
2519 }
2520 }
2521#endif
2522
2523 std::array<MFloat, nDist> eqDist;
2524 eqDist = getEqDists(l_rho, u.data());
2525 std::array<MFloat, nDist> eqDistT;
2526 eqDistT = getEqDistsThermal_<thermalMode>(l_t, l_rho, u.data());
2527 std::array<MFloat, nDist> eqDistC;
2528 eqDistC = getEqDistsTransport(l_c, u.data());
2529
2530 std::array<MFloat, nDist> Sj;
2531 IF_CONSTEXPR(thermalMode == 2) {
2532 std::array<MFloat, 2 * nDim> b{};
2533 for(MInt d = 0; d < nDim; d++) {
2534 b[2 * d] = -u[d];
2535 b[2 * d + 1] = u[d];
2536 }
2537 const MFloat sqVel = std::inner_product(&u[0], &u[nDim], &u[0], F0);
2538#ifdef WAR_NVHPC_PSTL
2539 for(MInt j = 0; j < m_distFld[0]; j++) {
2540 Sj[j] = (l_omegaT - l_omega) * (b[j] - sqVel * F1B2) * (a_oldDistribution(pCellId, j) - eqDist[j]);
2541 }
2542 for(MInt j = 0; j < m_distFld[1]; j++) {
2543 const MInt p = 2 * j;
2544 const MInt pos = j + m_distFld[0];
2545 const MFloat tmp = (b[m_mFld1[p]] + b[m_mFld1[p + 1]]);
2546 Sj[pos] = (l_omegaT - l_omega) * (tmp - sqVel * F1B2) * (a_oldDistribution(pCellId, pos) - eqDist[pos]);
2547 }
2548 for(MInt j = 0; j < m_distFld[2]; j++) {
2549 const MInt p = 3 * j;
2550 const MInt pos = j + m_distFld[0] + m_distFld[1];
2551 const MFloat tmp = (b[m_mFld2[p]] + b[m_mFld2[p + 1]] + b[m_mFld2[p + 2]]);
2552 Sj[pos] = (l_omegaT - l_omega) * (tmp - sqVel * F1B2) * (a_oldDistribution(pCellId, pos) - eqDist[pos]);
2553 }
2554 Sj[Ld::lastId()] = (l_omegaT - l_omega) * (F0 - sqVel * F1B2)
2555 * (a_oldDistribution(pCellId, Ld::lastId()) - eqDist[Ld::lastId()]);
2556#else
2557 for(MInt j = 0; j < Ld::distFld(0); j++) {
2558 Sj[j] = (l_omegaT - l_omega) * (b[j] - sqVel * F1B2) * (oldDistributionsStart[j] - eqDist[j]);
2559 }
2560 for(MInt j = 0; j < Ld::distFld(1); j++) {
2561 const MInt p = 2 * j;
2562 const MInt pos = j + Ld::distFld(0);
2563 const MFloat tmp = (b[Ld::mFld1(p)] + b[Ld::mFld1(p + 1)]);
2564 Sj[pos] = (l_omegaT - l_omega) * (tmp - sqVel * F1B2) * (oldDistributionsStart[pos] - eqDist[pos]);
2565 }
2566 for(MInt j = 0; j < Ld::distFld(2); j++) {
2567 const MInt p = 3 * j;
2568 const MInt pos = j + Ld::distFld(0) + Ld::distFld(1);
2569 const MFloat tmp = (b[Ld::mFld2(p)] + b[Ld::mFld2(p + 1)] + b[Ld::mFld2(p + 2)]);
2570 Sj[pos] = (l_omegaT - l_omega) * (tmp - sqVel * F1B2) * (oldDistributionsStart[pos] - eqDist[pos]);
2571 }
2572 Sj[Ld::lastId()] =
2573 (l_omegaT - l_omega) * (F0 - sqVel * F1B2) * (oldDistributionsStart[Ld::lastId()] - eqDist[Ld::lastId()]);
2574#endif
2575 }
2576
2577 // Calculation of new distributions
2578 for(MInt j = 0; j < nDist; j++) {
2579#ifdef WAR_NVHPC_PSTL
2580 a_distribution(pCellId, j) =
2581 a_oldDistribution(pCellId, j) + l_omega * (eqDist[j] - a_oldDistribution(pCellId, j));
2582 a_distributionThermal(pCellId, j) =
2583 a_oldDistributionThermal(pCellId, j) + l_omegaT * (eqDistT[j] - a_oldDistributionThermal(pCellId, j));
2584 a_distributionTransport(pCellId, j) =
2585 a_oldDistributionTransport(pCellId, j) + l_omegaD * (eqDistC[j] - a_oldDistributionTransport(pCellId, j));
2586 IF_CONSTEXPR(thermalMode == 2) { a_distributionThermal(pCellId, j) += Sj[j]; }
2587#else
2588 distributionsStart[j] = oldDistributionsStart[j] + l_omega * (eqDist[j] - oldDistributionsStart[j]);
2589 distributionsTStart[j] = oldDistributionsTStart[j] + l_omegaT * (eqDistT[j] - oldDistributionsTStart[j]);
2590 IF_CONSTEXPR(thermalMode == 2) { distributionsTStart[j] += Sj[j]; }
2591 distributionsTransportStart[j] = oldDistributionsTransportStart[j] + l_omegaD * (eqDistC[j] - oldDistributionsTransportStart[j]);
2592#endif
2593 }
2594 }
2595 });
2596}
2597
2603template <MInt nDim, MInt nDist, class SysEqn>
2605 TRACE();
2606
2607 bgki_thermal_and_transport_collision_step_base<0>();
2608}
2609
2615template <MInt nDim, MInt nDist, class SysEqn>
2617 TRACE();
2618
2619 bgki_thermal_and_transport_collision_step_base<1>();
2620}
2621
2627template <MInt nDim, MInt nDist, class SysEqn>
2629 TRACE();
2630
2631 bgki_thermal_and_transport_collision_step_base<2>();
2632}
2633
2634template <MInt nDim, MInt nDist, class SysEqn>
2635template <MInt thermalMode>
2637 TRACE();
2638
2639 const MInt pvrho = PV->RHO;
2640 const MInt pvt = PV->T;
2641
2642 constexpr MInt fldlen = Ld::dxQyFld();
2643
2644 // Update the global Reynolds number if we use the tanh-adaption
2645 if(m_tanhInit && (globalTimeStep > m_initStartTime)) {
2646 const MFloat scale =
2647 0.5 * (m_tanhScaleFactor * tanh((5.0 * (MFloat)(globalTimeStep - m_initStartTime) / (MFloat)m_initTime) - 2.5))
2648 + 0.5;
2649
2650 m_Re = m_initRe + scale * (m_finalRe - m_initRe);
2651
2652 // final timestep reached
2653 if(globalTimeStep == m_initStartTime + m_initTime) {
2654 m_Re = m_finalRe;
2655 m_tanhInit = 0;
2656 }
2657 }
2658
2659 // Update the according nu
2660 m_nu = m_Ma * LBCS / m_Re * m_referenceLength;
2661
2662 // Calculate heat diffusion coefficient
2663 m_kappa = m_nu / m_Pr;
2664
2665#ifndef WAR_NVHPC_PSTL
2666 // inner loop references
2667 const MInt* const RESTRICT activeCellList = ALIGNED_I(m_activeCellList);
2668 MFloat* const RESTRICT cnu = ALIGNED_MF(&(a_nu(0)));
2669 MFloat* const RESTRICT ckappa = ALIGNED_MF(&(a_kappa(0)));
2670 const MInt* const RESTRICT clevel = ALIGNED_I(&(this->m_cells.level(0)));
2671 MFloat* const RESTRICT oldDistributions = ALIGNED_MF(&(a_oldDistribution(0, 0)));
2672 MFloat* const RESTRICT distributions = ALIGNED_MF(&(a_distribution(0, 0)));
2673 MFloat* const RESTRICT oldDistributionsThermal = ALIGNED_MF(&(a_oldDistributionThermal(0, 0)));
2674 MFloat* const RESTRICT distributionsThermal = ALIGNED_MF(&(a_distributionThermal(0, 0)));
2675 MFloat* const RESTRICT variables = ALIGNED_MF(&(a_variable(0, 0)));
2676 const MFloat* const Fp = ALIGNED_MF(m_Fext);
2677 // members and globals
2678 const MInt maxLevel_ = maxLevel();
2679 // distances
2680 const MInt distNu = &a_nu(1) - &a_nu(0);
2681 const MInt distKappa = &a_kappa(1) - &a_kappa(0);
2682 const MInt distLevel = &(this->m_cells.level(1)) - &(this->m_cells.level(0));
2683 const MInt distVars = &(a_variable(1, 0)) - &(a_variable(0, 0));
2684#endif
2685 // Required for ported functions, since GPUs cannot access the global variable globalTimeStep
2686 const MInt gTS = globalTimeStep;
2687
2688 const MFloat factor = (thermalMode == 1) ? ((nDim == 2) ? 3.0 : 18.0 / 5.0) : F6;
2689
2690 // loop over all cells
2691 maia::parallelFor<true>(0, m_currentMaxNoCells, [=](MInt i) {
2692#ifdef WAR_NVHPC_PSTL
2693 const MInt pCellId = m_activeCellList[i];
2694 const MInt index = maxLevel() - this->a_level(pCellId);
2695#else
2696 const MInt pCellId = activeCellList[i];
2697 const MInt index = maxLevel_ - clevel[pCellId * distLevel];
2698#endif
2699
2700 // perform collision on finest level in every timestep,
2701 // on the next coarser level every second timestep, and so on
2702 if((gTS - 1) % IPOW2(index) == 0) {
2703 // save nu for bndcnd and interface interpolation
2704#ifndef WAR_NVHPC_PSTL
2705 cnu[pCellId * distNu] = m_nu;
2706 ckappa[pCellId * distKappa] = m_kappa;
2707
2708 const MInt distStart = pCellId * nDist;
2709 // varStart = (pCellId * distVars) + (distVarOldVar *
2710 // !((MInt)floor((MFloat)localGlobalTimeStep/fpow2[index]) % 2));
2711 const MInt varStart = pCellId * distVars;
2712
2713 MFloat* const oldDistributionsStart = &oldDistributions[distStart];
2714 MFloat* const distributionsStart = &distributions[distStart];
2715 MFloat* const oldDistributionsTStart = &oldDistributionsThermal[distStart];
2716 MFloat* const distributionsTStart = &distributionsThermal[distStart];
2717
2718 MFloat* const variablesStart = &variables[varStart];
2719#else
2720 a_nu(pCellId) = m_nu;
2721 a_kappa(pCellId) = m_kappa;
2722#endif
2723
2724 const MFloat tmp_FPOW2 = FPOW2(index);
2725 const MFloat tmp_FFPOW2 = FFPOW2(index);
2726 const MFloat l_omega = 2.0 / (1.0 + 6.0 * m_nu * tmp_FFPOW2);
2727 const MFloat l_omegaT = 2.0 / (1.0 + factor * m_kappa * tmp_FFPOW2);
2728
2729 swap_variables(pCellId);
2730
2731 // Reinit macroscopic variables before recalculation
2732 MFloat l_v[nDim] = {0.0};
2733 MFloat l_rho = 0.0;
2734 MFloat l_t = 0.0;
2735
2736#ifdef WAR_NVHPC_PSTL
2737 // Add forcing term and calculate density rho
2738 for(MInt j = 0; j < nDist - 1; j++) {
2739 IF_CONSTEXPR(thermalMode != 2) a_oldDistribution(pCellId, j) += tmp_FPOW2 * m_Fext[j];
2740 // Add forcing term and calculate density rho
2741 l_rho += a_oldDistribution(pCellId, j);
2742 l_t += a_oldDistributionThermal(pCellId, j);
2743 }
2744 // Do not forget the last distribution
2745 l_rho += a_oldDistribution(pCellId, nDist - 1);
2746 l_t += a_oldDistributionThermal(pCellId, nDist - 1);
2747#else
2748 // Add forcing term and calculate density rho
2749 for(MInt j = 0; j < nDist - 1; j++) {
2750 IF_CONSTEXPR(thermalMode != 2) oldDistributionsStart[j] += tmp_FPOW2 * Fp[j];
2751 l_rho += oldDistributionsStart[j];
2752 l_t += oldDistributionsTStart[j];
2753 }
2754 // Do not forget the last distribution
2755 l_rho += oldDistributionsStart[nDist - 1];
2756 l_t += oldDistributionsTStart[nDist - 1];
2757#endif
2758
2759 // Calculate macroscopic variables
2760#ifndef WAR_NVHPC_PSTL
2761 if constexpr(nDim == 2) {
2762 // WARNING!!! The velocity should be calculated as in 3d
2763 // However, result is correct
2764 // calculation of u
2765 l_v[0] = oldDistributionsStart[1] + oldDistributionsStart[4] + oldDistributionsStart[5]
2766 - oldDistributionsStart[7] - oldDistributionsStart[6] - oldDistributionsStart[0];
2767 // calculation of v
2768 l_v[1] = oldDistributionsStart[7] + oldDistributionsStart[3] + oldDistributionsStart[4]
2769 - oldDistributionsStart[6] - oldDistributionsStart[2] - oldDistributionsStart[5];
2770 } else {
2771#endif
2772 for(MInt j = 0; j < fldlen; j++) {
2773 for(MInt d = 0; d < nDim; d++) {
2774#ifdef WAR_NVHPC_PSTL
2775 l_v[d] += a_oldDistribution(pCellId, m_pFld[d * fldlen + j]);
2776 l_v[d] -= a_oldDistribution(pCellId, m_nFld[d * fldlen + j]);
2777#else
2778 l_v[d] += oldDistributionsStart[Ld::pFld(d, j)];
2779 l_v[d] -= oldDistributionsStart[Ld::nFld(d, j)];
2780#endif
2781 }
2782 }
2783#ifndef WAR_NVHPC_PSTL
2784 }
2785#endif
2786
2787 std::array<MFloat, nDim> u{};
2788 for(MInt d = 0; d < nDim; d++) {
2789 u[d] = l_v[d] / l_rho;
2790 }
2791
2792 // Save new macroscopic variables in cell
2793#ifdef WAR_NVHPC_PSTL
2794 for(MInt d = 0; d < nDim; d++) {
2795 a_variable(pCellId, d) = l_v[d];
2796 }
2797 a_variable(pCellId, pvrho) = l_rho;
2798 IF_CONSTEXPR(thermalMode == 0) { a_variable(pCellId, pvt) = l_t; }
2799 IF_CONSTEXPR(thermalMode == 1) {
2800 const MFloat D = (MFloat)nDim;
2801 const MFloat l_ie_rho = l_t;
2802 l_t = l_ie_rho * F2 / (D * l_rho);
2803 a_variable(pCellId, pvt) = l_t;
2804 }
2805 IF_CONSTEXPR(thermalMode == 2) {
2806 const MFloat accelerationForce = (this->m_externalForcing) ? m_densityGradient * F1B3 : F0;
2807 const MFloat D = (MFloat)nDim;
2808 // Set the external acceleratrion vector
2809 // So far only for a channel in x-direction
2810 std::array<MFloat, nDim> a{};
2811 a[0] = accelerationForce;
2812 for(MInt d = 0; d < nDim; d++) {
2813 l_v[d] += l_rho * tmp_FPOW2 * a[d] * F1B2;
2814 u[d] = l_v[d] / l_rho;
2815 }
2816 const MFloat sqVel = std::inner_product(&u[0], &u[nDim], &u[0], F0);
2817
2818 MFloat u_x_a = F0;
2819 for(MInt d = 0; d < nDim; d++) {
2820 u_x_a += u[d] * a[d];
2821 }
2822 const MFloat l_te_rho = l_t + F1B2 * tmp_FPOW2 * l_rho * u_x_a;
2823 l_t = (l_te_rho / l_rho - sqVel * F1B2) * F2 / D;
2824 a_variable(pCellId, pvt) = l_t;
2825 for(MInt d = 0; d < nDim; d++) {
2826 a_variable(pCellId, d) = l_v[d];
2827 }
2828 }
2829#else
2830 for(MInt d = 0; d < nDim; d++) {
2831 variablesStart[d] = l_v[d];
2832 }
2833 variablesStart[pvrho] = l_rho;
2834 IF_CONSTEXPR(thermalMode == 0) { variablesStart[pvt] = l_t; }
2835 IF_CONSTEXPR(thermalMode == 1) {
2836 const MFloat D = (MFloat)nDim;
2837 const MFloat l_ie_rho = l_t;
2838 l_t = l_ie_rho * F2 / (D * l_rho);
2839 variablesStart[pvt] = l_t;
2840 }
2841 IF_CONSTEXPR(thermalMode == 2) {
2842 const MFloat accelerationForce = (this->m_externalForcing) ? m_densityGradient * F1B3 : F0;
2843 const MFloat D = (MFloat)nDim;
2844 // Set the external acceleratrion vector
2845 // So far only for a channel in x-direction
2846 std::array<MFloat, nDim> a{};
2847 a[0] = accelerationForce;
2848 for(MInt d = 0; d < nDim; d++) {
2849 l_v[d] += l_rho * tmp_FPOW2 * a[d] * F1B2;
2850 u[d] = l_v[d] / l_rho;
2851 }
2852 const MFloat sqVel = std::inner_product(&u[0], &u[nDim], &u[0], F0);
2853
2854 MFloat u_x_a = F0;
2855 for(MInt d = 0; d < nDim; d++) {
2856 u_x_a += u[d] * a[d];
2857 }
2858 const MFloat l_te_rho = l_t + F1B2 * tmp_FPOW2 * l_rho * u_x_a;
2859 l_t = (l_te_rho / l_rho - sqVel * F1B2) * F2 / D;
2860 variablesStart[pvt] = l_t;
2861 for(MInt d = 0; d < nDim; d++) {
2862 variablesStart[d] = l_v[d];
2863 }
2864 }
2865#endif
2866
2867 std::array<MFloat, nDist> eqDist;
2868 eqDist = getEqDists(l_rho, u.data());
2869 std::array<MFloat, nDist> eqDistT;
2870 eqDistT = getEqDistsThermal_<thermalMode>(l_t, l_rho, u.data());
2871
2872 std::array<MFloat, nDist> forcing;
2873 std::array<MFloat, nDist> forcingT;
2874 std::array<MFloat, nDist> Sj;
2875 IF_CONSTEXPR(thermalMode == 2) {
2876 const MFloat accelerationForce = (this->m_externalForcing) ? m_densityGradient * F1B3 : F0;
2877 std::array<MFloat, 2 * nDim> a{};
2878 a[0] = -accelerationForce;
2879 a[1] = accelerationForce;
2880 MFloat u_x_a = F0;
2881 std::array<MFloat, 2 * nDim> b;
2882 for(MInt d = 0; d < nDim; d++) {
2883 b[2 * d] = -u[d];
2884 b[2 * d + 1] = u[d];
2885 u_x_a += b[d * 2 + 1] * a[d * 2 + 1];
2886 }
2887 const MFloat D = (MFloat)nDim;
2888 const MFloat sqVel = std::inner_product(&u[0], &u[nDim], &u[0], F0);
2889 const MFloat l_te_rho = (l_t * D * F1B2 + sqVel * F1B2) * l_rho;
2890#ifdef WAR_NVHPC_PSTL
2891 for(MInt j = 0; j < m_distFld[0]; j++) {
2892 forcing[j] = m_tp[1] * F1BCSsq * l_rho * (a[j] + a[j] * b[j] * F1BCSsq - u_x_a);
2893 Sj[j] = (l_omegaT - l_omega) * (b[j] - sqVel * F1B2)
2894 * (a_oldDistribution(pCellId, j) - eqDist[j] + F1B2 * tmp_FPOW2 * forcing[j]);
2895 forcingT[j] = m_tp[1] * F1BCSsq * l_te_rho * a[j] + a_oldDistribution(pCellId, j) * a[j];
2896 forcing[j] *= tmp_FPOW2 * (F1 - l_omega * F1B2);
2897 forcingT[j] *= tmp_FPOW2 * (F1 - l_omegaT * F1B2);
2898 }
2899 for(MInt j = 0; j < m_distFld[1]; j++) {
2900 const MInt p = 2 * j;
2901 const MInt pos = j + m_distFld[0];
2902 const MFloat tmp = (b[m_mFld1[p]] + b[m_mFld1[p + 1]]);
2903 const MFloat tmpT = (a[m_mFld1[p]] + a[m_mFld1[p + 1]]);
2904 forcing[pos] = m_tp[2] * F1BCSsq * l_rho * (tmpT + tmpT * tmp * F1BCSsq - u_x_a);
2905 Sj[pos] = (l_omegaT - l_omega) * (tmp - sqVel * F1B2)
2906 * (a_oldDistribution(pCellId, pos) - eqDist[pos] + F1B2 * tmp_FPOW2 * forcing[pos]);
2907 forcingT[pos] = m_tp[2] * F1BCSsq * l_te_rho * tmpT + a_oldDistribution(pCellId, pos) * tmpT;
2908 forcing[pos] *= tmp_FPOW2 * (F1 - l_omega * F1B2);
2909 forcingT[pos] *= tmp_FPOW2 * (F1 - l_omegaT * F1B2);
2910 }
2911 for(MInt j = 0; j < m_distFld[2]; j++) {
2912 const MInt p = 3 * j;
2913 const MInt pos = j + m_distFld[0] + m_distFld[1];
2914 const MFloat tmp = (b[m_mFld2[p]] + b[m_mFld2[p + 1]] + b[m_mFld2[p + 2]]);
2915 const MFloat tmpT = (a[m_mFld2[p]] + a[m_mFld2[p + 1]] + a[m_mFld2[p + 2]]);
2916 forcing[pos] = m_tp[3] * F1BCSsq * l_rho * (tmpT + tmpT * tmp * F1BCSsq - u_x_a);
2917 Sj[pos] = (l_omegaT - l_omega) * (tmp - sqVel * F1B2)
2918 * (a_oldDistribution(pCellId, pos) - eqDist[pos] + F1B2 * tmp_FPOW2 * forcing[pos]);
2919 forcingT[pos] = m_tp[3] * F1BCSsq * l_te_rho * tmpT + a_oldDistribution(pCellId, pos) * tmpT;
2920 forcing[pos] *= tmp_FPOW2 * (F1 - l_omega * F1B2);
2921 forcingT[pos] *= tmp_FPOW2 * (F1 - l_omegaT * F1B2);
2922 }
2923 forcing[Ld::lastId()] = m_tp[0] * l_rho * (-F1BCSsq * u_x_a);
2924 Sj[Ld::lastId()] = (l_omegaT - l_omega) * (F0 - sqVel * F1B2)
2925 * (a_oldDistribution(pCellId, Ld::lastId()) - eqDist[Ld::lastId()]
2926 + F1B2 * tmp_FPOW2 * forcing[Ld::lastId()]);
2927 forcingT[Ld::lastId()] = F0;
2928 forcing[Ld::lastId()] *= tmp_FPOW2 * (F1 - l_omega * F1B2);
2929#else
2930 for(MInt j = 0; j < Ld::distFld(0); j++) {
2931 forcing[j] = Ld::tp(1) * F1BCSsq * l_rho * (a[j] + a[j] * b[j] * F1BCSsq - u_x_a);
2932 Sj[j] = (l_omegaT - l_omega) * (b[j] - sqVel * F1B2)
2933 * (oldDistributionsStart[j] - eqDist[j] + F1B2 * tmp_FPOW2 * forcing[j]);
2934 forcingT[j] = Ld::tp(1) * F1BCSsq * l_te_rho * a[j] + oldDistributionsStart[j] * a[j];
2935 forcing[j] *= tmp_FPOW2 * (F1 - l_omega * F1B2);
2936 forcingT[j] *= tmp_FPOW2 * (F1 - l_omegaT * F1B2);
2937 }
2938 for(MInt j = 0; j < Ld::distFld(1); j++) {
2939 const MInt p = 2 * j;
2940 const MInt pos = j + Ld::distFld(0);
2941 const MFloat tmp = (b[Ld::mFld1(p)] + b[Ld::mFld1(p + 1)]);
2942 const MFloat tmpT = (a[Ld::mFld1(p)] + a[Ld::mFld1(p + 1)]);
2943 forcing[pos] = Ld::tp(2) * F1BCSsq * l_rho * (tmpT + tmpT * tmp * F1BCSsq - u_x_a);
2944 Sj[pos] = (l_omegaT - l_omega) * (tmp - sqVel * F1B2)
2945 * (oldDistributionsStart[pos] - eqDist[pos] + F1B2 * tmp_FPOW2 * forcing[pos]);
2946 forcingT[pos] = Ld::tp(2) * F1BCSsq * l_te_rho * tmpT + oldDistributionsStart[pos] * tmpT;
2947 forcing[pos] *= tmp_FPOW2 * (F1 - l_omega * F1B2);
2948 forcingT[pos] *= tmp_FPOW2 * (F1 - l_omegaT * F1B2);
2949 }
2950 for(MInt j = 0; j < Ld::distFld(2); j++) {
2951 const MInt p = 3 * j;
2952 const MInt pos = j + Ld::distFld(0) + Ld::distFld(1);
2953 const MFloat tmp = (b[Ld::mFld2(p)] + b[Ld::mFld2(p + 1)] + b[Ld::mFld2(p + 2)]);
2954 const MFloat tmpT = (a[Ld::mFld2(p)] + a[Ld::mFld2(p + 1)] + a[Ld::mFld2(p + 2)]);
2955 forcing[pos] = Ld::tp(3) * F1BCSsq * l_rho * (tmpT + tmpT * tmp * F1BCSsq - u_x_a);
2956 Sj[pos] = (l_omegaT - l_omega) * (tmp - sqVel * F1B2)
2957 * (oldDistributionsStart[pos] - eqDist[pos] + F1B2 * tmp_FPOW2 * forcing[pos]);
2958 forcingT[pos] = Ld::tp(3) * F1BCSsq * l_te_rho * tmpT + oldDistributionsStart[pos] * tmpT;
2959 forcing[pos] *= tmp_FPOW2 * (F1 - l_omega * F1B2);
2960 forcingT[pos] *= tmp_FPOW2 * (F1 - l_omegaT * F1B2);
2961 }
2962 forcing[Ld::lastId()] = Ld::tp(0) * l_rho * (-F1BCSsq * u_x_a);
2963 Sj[Ld::lastId()] =
2964 (l_omegaT - l_omega) * (F0 - sqVel * F1B2)
2965 * (oldDistributionsStart[Ld::lastId()] - eqDist[Ld::lastId()] + F1B2 * tmp_FPOW2 * forcing[Ld::lastId()]);
2966 forcingT[Ld::lastId()] = F0;
2967 forcing[Ld::lastId()] *= tmp_FPOW2 * (F1 - l_omega * F1B2);
2968#endif
2969 }
2970
2971 // Calculation of new distributions
2972 for(MInt j = 0; j < nDist; j++) {
2973#ifdef WAR_NVHPC_PSTL
2974 a_distribution(pCellId, j) =
2975 a_oldDistribution(pCellId, j) + l_omega * (eqDist[j] - a_oldDistribution(pCellId, j));
2976 a_distributionThermal(pCellId, j) =
2977 a_oldDistributionThermal(pCellId, j) + l_omegaT * (eqDistT[j] - a_oldDistributionThermal(pCellId, j));
2978 IF_CONSTEXPR(thermalMode == 2) {
2979 a_distribution(pCellId, j) += forcing[j];
2980 a_distributionThermal(pCellId, j) += forcingT[j] + Sj[j];
2981 }
2982#else
2983 distributionsStart[j] = oldDistributionsStart[j] + l_omega * (eqDist[j] - oldDistributionsStart[j]);
2984 distributionsTStart[j] = oldDistributionsTStart[j] + l_omegaT * (eqDistT[j] - oldDistributionsTStart[j]);
2985 IF_CONSTEXPR(thermalMode == 2) {
2986 distributionsStart[j] += forcing[j];
2987 distributionsTStart[j] += forcingT[j] + Sj[j];
2988 }
2989#endif
2990 }
2991 }
2992 });
2993}
2994
3003template <MInt nDim, MInt nDist, class SysEqn>
3005 TRACE();
3006
3007 bgki_thermal_collision_step_base<0>();
3008}
3009
3010
3034template <MInt nDim, MInt nDist, class SysEqn>
3036 TRACE();
3037
3038 bgki_thermal_collision_step_base<1>();
3039}
3040
3060template <MInt nDim, MInt nDist, class SysEqn>
3062 TRACE();
3063
3064 bgki_thermal_collision_step_base<2>();
3065}
3066
3075template <MInt nDim, MInt nDist, class SysEqn>
3077 bgki_smagorinsky_collision_step_base<0>();
3078}
3079
3089template <MInt nDim, MInt nDist, class SysEqn>
3091 bgki_smagorinsky_collision_step_base<1>();
3092}
3093
3103template <MInt nDim, MInt nDist, class SysEqn>
3105 bgki_smagorinsky_collision_step_base<2>();
3106}
3107
3108template <MInt nDim, MInt nDist, class SysEqn>
3109template <MInt mode>
3111 TRACE();
3112
3113 // For now testing only the D3Q19 algorithm
3114 MFloat rho = F0;
3115 MFloat Q = F0;
3116 MFloat tau = F0;
3117 MFloat S = F0;
3118
3119 MInt index = 0;
3120 MFloat actualCellLength = F0;
3121 constexpr MInt direction = 1;
3122
3123 MChar buf[10];
3124 MString fileName;
3125 ofstream ofl;
3126
3127 ScratchSpace<MFloat> diss(m_arraySize[direction], AT_, "diss");
3128 ScratchSpace<MFloat> totalDiss(m_arraySize[direction], AT_, "totalDiss");
3129 ScratchSpace<MFloat> SGSDiss(m_arraySize[direction], AT_, "SGSDiss");
3130 ScratchSpace<MFloat> totalSGSDiss(m_arraySize[direction], AT_, "totalSGSDiss");
3131 MFloat energy;
3132
3133 // reset dissipation and energy values
3134 for(MInt i = 0; i < m_arraySize[direction]; i++) {
3135 diss[i] = F0;
3136 SGSDiss[i] = F0;
3137 }
3138
3139 energy = F0;
3140
3141 if(m_tanhInit && (globalTimeStep > m_initStartTime)) {
3142 MFloat scale =
3143 0.5 * (m_tanhScaleFactor * tanh((5.0 * (MFloat)(globalTimeStep - m_initStartTime) / (MFloat)m_initTime) - 2.5))
3144 + 0.5;
3145
3146 m_Re = m_initRe + scale * (m_finalRe - m_initRe);
3147
3148 // final timestep reached
3149 if(globalTimeStep == m_initStartTime + m_initTime) {
3150 m_Re = m_finalRe;
3151 m_tanhInit = 0;
3152 }
3153 }
3154 m_nu = m_Ma * LBCS / m_Re * m_referenceLength;
3155
3156 for(MInt i = 0; i < m_currentMaxNoCells; i++) {
3157 const MInt pCellId = m_activeCellList[i];
3158
3159 if((globalTimeStep - 1) % IPOW2(maxLevel() - this->a_level(pCellId))
3160 == 0) { // perform collision on finest level in every timestep, // on the next coarser level every second
3161 // timestep, and so on
3162
3163 swap_variables(pCellId);
3164
3165 // Calculate macroscopic variables
3166 a_variable(pCellId, PV->RHO) = 0.0;
3167 for(MInt j = 0; j < nDist; j++) {
3168 a_variable(pCellId, PV->RHO) += a_oldDistribution(pCellId, j);
3169 }
3170 rho = a_variable(pCellId, PV->RHO);
3171
3172 MFloat u[nDim];
3173 for(MInt j = 0; j < nDim; j++) {
3174 u[j] = F0;
3175 }
3176
3177 if constexpr(nDim == 2) {
3178 // warning!!! the velocity should be calculated as in 3d
3179 // however, result is correct
3180 // calculation of u
3181 u[0] = a_oldDistribution(pCellId, 1) + a_oldDistribution(pCellId, 4) + a_oldDistribution(pCellId, 5)
3182 - a_oldDistribution(pCellId, 7) - a_oldDistribution(pCellId, 6) - a_oldDistribution(pCellId, 0);
3183 // calculation of v
3184 u[1] = a_oldDistribution(pCellId, 7) + a_oldDistribution(pCellId, 3) + a_oldDistribution(pCellId, 4)
3185 - a_oldDistribution(pCellId, 6) - a_oldDistribution(pCellId, 2) - a_oldDistribution(pCellId, 5);
3186 } else {
3187 for(MInt j = 0; j < Ld::dxQyFld(); j++) {
3188 for(MInt d = 0; d < nDim; d++) {
3189 u[d] += a_oldDistribution(pCellId, Ld::pFld(d, j));
3190 u[d] -= a_oldDistribution(pCellId, Ld::nFld(d, j));
3191 }
3192 }
3193 }
3194
3195 for(MInt j = 0; j < nDim; j++) {
3196 a_variable(pCellId, j) = u[j];
3197 }
3198
3199 // Calculation of equilibrium and non-equilibrium distribution
3200 std::array<MFloat, nDist> eqDist;
3201 eqDist = getEqDists(rho, u);
3202
3203 MFloat nonEqDist[nDist];
3204 for(MInt j = 0; j < nDist; j++) {
3205 nonEqDist[j] = a_oldDistribution(pCellId, j) - eqDist[j];
3206 }
3207
3208 //--------------------------------------------
3209 // Calculation of overall viscosity
3210 // according to Hu, Sterling, Chen 1994
3211
3212 // 1. Calculation of original relaxation time (on current level)
3213 tau = F1B2 + 3.0 * m_nu * FFPOW2(maxLevel() - this->a_level(pCellId));
3214
3215 // 2. Calculation of momentum flux tensor from non-equilibrium parts
3216 calculateMomentumFlux(pCellId);
3217
3218 // 3. Calculation of the filtered mean momentum flux
3219 Q = 0.0;
3220 for(MInt k = 0; k < nDim * nDim; k++) {
3221 Q += m_momentumFlux[pCellId][k] * m_momentumFlux[pCellId][k];
3222 }
3223 Q = sqrt(2.0 * Q);
3224
3225 // 4. Calculation of new relaxation time
3226 if(mode == 1) {
3227 const MFloat aPlus = 26.0;
3228 MFloat tmpWidth = m_referenceLength * m_smallestCellLength;
3229 MFloat yPlus = m_ReTau * (1.0 - fabs(a_coordinate(pCellId, 1)) / tmpWidth);
3230 MFloat lambda = m_Cs * m_deltaX * (F1 - exp(-yPlus / aPlus));
3231 tau += F1B2
3232 * (sqrt(tau * tau
3233 + 2.0 * SQRT2 * lambda * lambda * (F1BCSsq * F1BCSsq) * Q
3234 * FPOW2(maxLevel() - this->a_level(pCellId)))
3235 - tau);
3236 } else {
3237 tau += F1B2
3238 * (sqrt(tau * tau
3239 + 2.0 * SQRT2 * m_Cs * m_Cs * m_deltaX * m_deltaX * (F1BCSsq * F1BCSsq) * Q
3240 * FPOW2(maxLevel() - this->a_level(pCellId)))
3241 - tau);
3242 }
3243
3244 m_omega = 1.0 / tau;
3245
3246 // save total nu for bndcnd and interface interpolation (save on finest level)
3247 a_nu(pCellId) = FPOW2(maxLevel() - this->a_level(pCellId)) * (tau - F1B2) / 3.0;
3248
3249 //--------------------------------------------
3250
3251 // perform relaxation
3252 for(MInt j = 0; j < nDist; j++) {
3253 a_distribution(pCellId, j) = a_oldDistribution(pCellId, j) - m_omega * nonEqDist[j];
3254 }
3255
3256
3257 //---------------------------
3258 // save dissipation values
3259 if(mode == 2) {
3260 actualCellLength = this->c_cellLengthAtLevel(this->a_level(pCellId));
3261 index = floor(
3262 (F1B2 * m_arraySize[direction]
3263 + (a_coordinate(pCellId, direction) - F1B2 * (actualCellLength)) / (this->c_cellLengthAtLevel(maxLevel())))
3264 + 0.1);
3265
3266 // Calculate characteristic filtered rate of strain
3267 S = F1B2 * F1BCSsq * m_omega * Q;
3268
3269 // Calculate molecular- and subgrid dissipation
3270 if(pCellId < this->grid().noInternalCells()) {
3271 diss[index] += m_nu * S * S;
3272 SGSDiss[index] += m_Cs * m_Cs * m_deltaX * m_deltaX * S * S * S * FPOW4(maxLevel() - this->a_level(pCellId));
3273 for(MInt d = 0; d < nDim; d++) {
3274 energy += F1B2 * (a_variable(pCellId, d) * a_variable(pCellId, d));
3275 }
3276 }
3277 }
3278 }
3279 }
3280
3281 // write dissipation values
3282 if(mode == 2 && globalTimeStep % m_solutionInterval == 0) {
3283 // for (MInt i=0; i<m_arraySize[direction]; i++){
3284 // m_log <<"cs["<<i<<"]="<<dynamicCs[i]<<endl;
3285 // }
3286
3287 // all domains send their information to domain_0
3288 if(domainId() != 0) {
3289 MPI_Send(&(diss[0]), m_arraySize[direction], MPI_DOUBLE, 0, 0, mpiComm(), AT_, "(diss[0])");
3290 MPI_Send(&(SGSDiss[0]), m_arraySize[direction], MPI_DOUBLE, 0, 0, mpiComm(), AT_, "(SGSDiss[0])");
3291 MPI_Send(&energy, 1, MPI_DOUBLE, 0, 0, mpiComm(), AT_, "energy");
3292 }
3293
3294 if(domainId() == 0) {
3295 MPI_Status status;
3296
3297 for(MInt i = 0; i < m_arraySize[direction]; i++) {
3298 totalDiss[i] = diss[i];
3299 totalSGSDiss[i] = SGSDiss[i];
3300 }
3301
3302 for(MInt j = 1; j < noDomains(); j++) {
3303 MPI_Recv(&(diss[0]), m_arraySize[direction], MPI_DOUBLE, j, 0, mpiComm(), &status, AT_, "(diss[0])");
3304 MPI_Recv(&(SGSDiss[0]), m_arraySize[direction], MPI_DOUBLE, j, 0, mpiComm(), &status, AT_, "(SGSDiss[0])");
3305 MPI_Recv(&energy, 1, MPI_DOUBLE, j, 0, mpiComm(), &status, AT_, "energy");
3306 for(MInt i = 0; i < m_arraySize[direction]; i++) {
3307 totalDiss[i] += diss[i];
3308 totalSGSDiss[i] += SGSDiss[i];
3309 }
3310 }
3311
3312 fileName = "totalDiss_";
3313 sprintf(buf, "%d", globalTimeStep);
3314 fileName += buf;
3315 fileName += ".dat";
3316 m_log << "writing diss file: " << fileName << endl;
3317 ofl.open(fileName.c_str(), ios_base::out);
3318 for(MInt i = 0; i < m_arraySize[direction]; i++)
3319 ofl << globalTimeStep << " " << i << " " << totalDiss[i] << " " << totalSGSDiss[i] << " " << energy << endl;
3320 ofl.close();
3321 }
3322 }
3323}
3324
3333template <MInt nDim, MInt nDist, class SysEqn>
3335 TRACE();
3336
3337 updateMacroscopicVariables();
3338 for(MInt i = 0; i < this->noInternalCells(); i++) {
3339 calculateMomentumFlux(i);
3340 }
3341 calculateSGSTensors();
3342
3343 std::vector<MFloat> dynamicCs;
3344 constexpr MInt direction = 1;
3345 MInt count = 0;
3346 averageSGSTensors(direction, count, dynamicCs);
3347
3348 for(MInt i = 0; i < count; i++) {
3349 if(dynamicCs[i] < 0.0) dynamicCs[i] = 0.0;
3350 }
3351
3352
3353 // For now testing only the D3Q19 algorithm
3354 MFloat rho = F1;
3355 MFloat u[nDim] = {F0};
3356 MFloat tau = F0;
3357
3358 MFloat Q = F0;
3359 MInt index = 0;
3360 MFloat actualCellLength = F0;
3361
3362 if(m_tanhInit && (globalTimeStep > m_initStartTime)) {
3363 MFloat scale =
3364 0.5 * (m_tanhScaleFactor * tanh((5.0 * (MFloat)(globalTimeStep - m_initStartTime) / (MFloat)m_initTime) - 2.5))
3365 + 0.5;
3366
3367 m_Re = m_initRe + scale * (m_finalRe - m_initRe);
3368
3369 // final timestep reached
3370 if(globalTimeStep == m_initStartTime + m_initTime) {
3371 m_Re = m_finalRe;
3372 m_tanhInit = 0;
3373 }
3374 }
3375 m_nu = m_Ma * LBCS / m_Re * m_referenceLength;
3376
3377 for(MInt i = 0; i < m_currentMaxNoCells; i++) {
3378 const MInt pCellId = m_activeCellList[i];
3379
3380 if((globalTimeStep - 1) % IPOW2(maxLevel() - this->a_level(pCellId)) == 0) {
3381 rho = a_variable(pCellId, PV->RHO);
3382
3383 for(MInt d = 0; d < nDim; d++) {
3384 u[d] = a_variable(pCellId, d);
3385 }
3386
3387 // Calculation of equilibrium and non-equilibrium distribution
3388 std::array<MFloat, nDist> eqDist;
3389 eqDist = getEqDists(rho, u);
3390 MFloat nonEqDist[nDist];
3391 for(MInt j = 0; j < nDist; j++) {
3392 nonEqDist[j] = a_oldDistribution(pCellId, j) - eqDist[j];
3393 }
3394
3395 //--------------------------------------------
3396 // Calculation of overall viscosity
3397 // according to Hu, Sterling, Chen 1994
3398
3399 // Calculation of original relaxation time (on current level)
3400 tau = F1B2 + 3.0 * m_nu * FFPOW2(maxLevel() - this->a_level(pCellId));
3401
3402 // Calculate square of momentum flux tensor
3403 Q = 0.0;
3404 for(MInt k = 0; k < nDim * nDim; k++) {
3405 Q += m_momentumFlux[pCellId][k] * m_momentumFlux[pCellId][k];
3406 }
3407 Q = sqrt(2.0 * Q);
3408
3409 // Calculation of new relaxation time
3410
3411 // index = (MInt)((a_coordinate(pCellId, direction) - minCoord) / length * MFloat(count - 1) + 0.5);
3412 index = floor((F1B2 * count
3413 + (a_coordinate(pCellId, 1) - F1B2 * (actualCellLength)) / (this->c_cellLengthAtLevel(maxLevel())))
3414 + 0.1);
3415
3416 tau += F1B2
3417 * (sqrt(tau * tau
3418 + 2.0 * SQRT2 * dynamicCs[index] * m_deltaX * m_deltaX * (F1BCSsq * F1BCSsq) * Q
3419 * FPOW2(maxLevel() - this->a_level(pCellId)))
3420 - tau);
3421
3422 m_omega = 1.0 / tau;
3423
3424 // save total nu for bndcnd and interface interpolation (save on finest level)
3425 a_nu(pCellId) = FPOW2(maxLevel() - this->a_level(pCellId)) * (tau - F1B2) / 3.0;
3426
3427 // perform relaxation
3428 for(MInt j = 0; j < nDist; j++) {
3429 a_distribution(pCellId, j) = a_oldDistribution(pCellId, j) - m_omega * nonEqDist[j];
3430 }
3431 }
3432 }
3433}
3434
3435
3444template <MInt nDim, MInt nDist, class SysEqn>
3446 TRACE();
3447
3448 const MInt pvrho = PV->RHO;
3449
3450 constexpr MInt fldlen = Ld::dxQyFld();
3451
3452 MFloat l_rho = 1.0;
3453 MFloat l_v[nDim] = {0.0};
3454
3455 MFloat eps = 1e-4;
3456
3457 // Update the global Reynolds number if we use the tanh-adaption
3458 if(m_tanhInit && (globalTimeStep > m_initStartTime)) {
3459 const MFloat scale =
3460 0.5 * (m_tanhScaleFactor * tanh((5.0 * (MFloat)(globalTimeStep - m_initStartTime) / (MFloat)m_initTime) - 2.5))
3461 + 0.5;
3462
3463 m_Re = m_initRe + scale * (m_finalRe - m_initRe);
3464
3465 // final timestep reached
3466 if(globalTimeStep == m_initStartTime + m_initTime) {
3467 m_Re = m_finalRe;
3468 m_tanhInit = 0;
3469 }
3470 }
3471
3472 // Update the according nu
3473 m_nu = m_Ma * LBCS / m_Re * m_referenceLength;
3474
3475
3476 for(MInt i = 0; i < m_currentMaxNoCells; i++) {
3477 const MInt pCellId = m_activeCellList[i];
3478
3479 if((globalTimeStep - 1) % IPOW2(maxLevel() - this->a_level(pCellId)) == 0) {
3480 a_oldVariable(i, PV->RHO) = a_variable(i, PV->RHO);
3481 a_oldVariable(i, PV->U) = a_variable(i, PV->U);
3482 a_oldVariable(i, PV->V) = a_variable(i, PV->V);
3483
3484 // Add forcing term and calculate density rho
3485 l_rho = F0;
3486 for(MInt j = 0; j < nDist - 1; j++) {
3487 l_rho += a_oldDistribution(pCellId, j);
3488 }
3489 // Do not forget the last distribution
3490 l_rho += a_oldDistribution(pCellId, nDist - 1);
3491
3492
3493 // Calculate macroscopic variables
3494 l_v[0] = F0;
3495 l_v[1] = F0;
3496 if constexpr(nDim == 3) l_v[2] = F0;
3497
3498 if constexpr(nDim == 2) {
3499 // WARNING!!! The velocity should be calculated as in 3d
3500 // However, result is correct
3501 // calculation of u
3502 l_v[0] = a_oldDistribution(pCellId, 1) + a_oldDistribution(pCellId, 4) + a_oldDistribution(pCellId, 5)
3503 - a_oldDistribution(pCellId, 7) - a_oldDistribution(pCellId, 6) - a_oldDistribution(pCellId, 0);
3504 // calculation of v
3505 l_v[1] = a_oldDistribution(pCellId, 7) + a_oldDistribution(pCellId, 3) + a_oldDistribution(pCellId, 4)
3506 - a_oldDistribution(pCellId, 6) - a_oldDistribution(pCellId, 2) - a_oldDistribution(pCellId, 5);
3507 } else {
3508 for(MInt j = 0; j < fldlen; j++) {
3509 for(MInt d = 0; d < nDim; d++) {
3510 l_v[d] += a_oldDistribution(pCellId, Ld::pFld(d, j));
3511 l_v[d] -= a_oldDistribution(pCellId, Ld::nFld(d, j));
3512 }
3513 }
3514 }
3515
3516 // Save new macroscopic variables in cell
3517 for(MInt d = 0; d < nDim; d++) {
3518 a_variable(pCellId, d) = l_v[d];
3519 }
3520 a_variable(pCellId, pvrho) = l_rho;
3521
3522 calculateMomentumFlux(pCellId);
3523
3524 // 3. Calculation of the filtered mean momentum flux
3525 MFloat Q = 0.0;
3526 for(MInt k = 0; k < nDim * nDim; k++) {
3527 Q += m_momentumFlux[pCellId][k] * m_momentumFlux[pCellId][k];
3528 }
3529 Q = sqrt(2.0 * Q);
3530
3531 for(MInt d = 0; d < nDim; d++) {
3532 l_v[d] = a_variable(pCellId, d);
3533 }
3534 l_rho = a_variable(pCellId, pvrho);
3535
3536 const MFloat sqVel = std::inner_product(&l_v[0], &l_v[nDim], &l_v[0], F0);
3537
3538 std::array<MFloat, nDist> eqDist;
3539 eqDist = getEqDists(l_rho, sqVel, l_v);
3540
3541 // Calculation of new distributions
3542 if(fabs(Q) > eps) {
3543 const MFloat l_omega = 2.0 / (1.0 + 6.0 * m_nu * FFPOW2(maxLevel() - this->a_level(pCellId)));
3544
3545 // Calculation of new distributions
3546 for(MInt j = 0; j < nDist; j++) {
3547 a_distribution(pCellId, j) =
3548 a_oldDistribution(pCellId, j) + l_omega * (eqDist[j] - a_oldDistribution(pCellId, j));
3549 }
3550 } else {
3551 // Calculation of new distributions
3552 for(MInt j = 0; j < nDist; j++) {
3553 a_distribution(pCellId, j) = eqDist[j];
3554 }
3555 }
3556 }
3557 }
3558}
3559
3563template <MInt nDim, MInt nDist, class SysEqn>
3565 TRACE();
3566
3567 if(globalTimeStep % 5 != 0) {
3568 return;
3569 }
3570
3571 constexpr MInt nDimSqr = nDim * nDim;
3572 constexpr MInt direction = 1;
3573
3574 // reset dissipation and energy values
3575 ScratchSpace<MFloat> diss(m_arraySize[direction], AT_, "diss");
3576 ScratchSpace<MFloat> SGSDiss(m_arraySize[direction], AT_, "SGSDiss");
3577 diss.fill(F0);
3578 SGSDiss.fill(F0);
3579 MFloat energy = 0.0;
3580
3581 m_nu = m_Ma * LBCS / m_Re * m_referenceLength;
3582
3583 for(MInt i = 0; i < m_currentMaxNoCells; i++) {
3584 const MInt pCellId = m_activeCellList[i];
3585
3586 calculateMomentumFlux(pCellId);
3587
3588 // skip lower levels
3589 if(this->a_level(pCellId) < maxLevel()) continue;
3590
3591 // // Calculate gradients
3592 // for(MInt var = 0; var < nDim; var++) {
3593 // for(MInt dir = 0; dir < nDim; dir++) {
3594 // L = c;
3595 // R = c;
3596 // if(a_hasNeighbor(c, 2 * dir) > 0) L = c_neighborId(c, 2 * dir);
3597 // if(a_hasNeighbor(c, 2 * dir + 1) > 0) R = c_neighborId(c, 2 * dir + 1);
3598 // if(L == c) {
3599 // gradV[var + 3 * dir] = (a_variable(R, var) - a_variable(c, var));
3600 // continue;
3601 // }
3602 // if(R == c) {
3603 // gradV[var + 3 * dir] = (a_variable(c, var) - a_variable(L, var));
3604 // continue;
3605 // }
3606 // gradV[var + 3 * dir] = (a_variable(R, var) - a_variable(L, var)) / 2.0;
3607 // }
3608 // }
3609
3610 // Calculate strain rate tensor
3611 // S_{ij} = \frac{1}{2} \partial_j u_i \partial_i u_j
3612 m_omega = 2.0 / (1.0 + 6.0 * m_nu * FPOW2(maxLevel() - this->a_level(pCellId)));
3613 MFloat Sij[nDimSqr];
3614 for(MInt k = 0; k < nDimSqr; k++) {
3615 Sij[k] = -F1B2 * F1BCSsq * m_omega * m_momentumFlux[i][k];
3616 }
3617
3618 // Calculate characteristic filtered rate of strain
3619 const MFloat Ssqr = 2.0 * std::inner_product(&Sij[0], &Sij[nDimSqr], &Sij[0], .0);
3620 const MFloat S = sqrt(Ssqr);
3621
3622 // Calculate molecular- and subgrid dissipation
3623 const MInt actualCellLength = this->c_cellLengthAtLevel(this->a_level(pCellId));
3624 const MInt index = floor(
3625 (F1B2 * m_arraySize[direction]
3626 + (a_coordinate(pCellId, direction) - F1B2 * (actualCellLength)) / (this->c_cellLengthAtLevel(maxLevel())))
3627 + 0.1);
3628 diss[index] += m_nu * Ssqr;
3629 SGSDiss[index] += m_Cs * m_Cs * m_deltaX * m_deltaX * S * S * S * FPOW4(maxLevel() - this->a_level(pCellId));
3630
3631 // energy
3632 MFloat tmp = 0.0;
3633 for(MInt k = 0; k < nDim; k++) {
3634 tmp += a_variable(pCellId, k) * a_variable(pCellId, k);
3635 }
3636 energy += F1B2 * tmp;
3637 }
3638
3639 // Sum-up on root domain
3640 constexpr MInt rootId = 0;
3641 MPI_Reduce(MPI_IN_PLACE, &diss[0], m_arraySize[direction], MPI_DOUBLE, MPI_SUM, rootId, mpiComm(), AT_,
3642 "MPI_IN_PLACE", "diss");
3643 MPI_Reduce(MPI_IN_PLACE, &SGSDiss[0], m_arraySize[direction], MPI_DOUBLE, MPI_SUM, rootId, mpiComm(), AT_,
3644 "MPI_IN_PLACE", "SGSDiss");
3645 MPI_Reduce(MPI_IN_PLACE, &energy, m_arraySize[direction], MPI_DOUBLE, MPI_SUM, rootId, mpiComm(), AT_, "MPI_IN_PLACE",
3646 "energy");
3647
3648 // Write out data from root process
3649 if(domainId() == rootId) {
3650 ofstream ofl;
3651 MString fileName = "totalDiss_";
3652 MChar buf[10];
3653 sprintf(buf, "%d", globalTimeStep);
3654 fileName += buf;
3655 fileName += ".dat";
3656 m_log << "writing diss file: " << fileName << endl;
3657 ofl.open(fileName.c_str(), ios_base::out);
3658 for(MInt i = 0; i < m_arraySize[direction]; i++)
3659 ofl << globalTimeStep << " " << i << " " << diss[i] << " " << SGSDiss[i] << " " << energy << endl;
3660 ofl.close();
3661 }
3662}
3663
3674template <MInt nDim, MInt nDist, class SysEqn>
3675template <MBool optimized, MBool useSmagorinsky>
3677 TERMM(1, "MRT collision step only available for D2Q9 and D3Q19 !");
3678}
3679
3680template <>
3681template <MBool optimized, MBool useSmagorinsky>
3683 TRACE();
3684 constexpr MInt nDist = 9;
3685 // constexpr MInt nDim = 2;
3686
3687 constexpr MFloat c1 = -2.0, alpha2 = -8.0, alpha3 = 4.0, gamma1 = F2B3, gamma3 = F2B3, gamma2 = 18.0, gamma4 = -18.0;
3688
3689 for(MInt i = 0; i < m_currentMaxNoCells; i++) {
3690 const MInt pCellId = m_activeCellList[i];
3691 const MInt lvlDiff = maxLevel() - this->a_level(pCellId);
3692 if((globalTimeStep - 1) % IPOW2(lvlDiff) == 0) {
3693 std::array<MFloat, nDist> d{};
3694 for(MInt j = 0; j < nDist; j++) {
3695 d[j] = a_oldDistribution(pCellId, j);
3696 }
3697
3698 std::array<MFloat, nDist> m{};
3699 m[0] = d[8] + d[1] + d[3] + d[0] + d[2] + d[4] + d[7] + d[6] + d[5];
3700 m[1] = -4 * d[8] - d[1] - d[3] - d[0] - d[2] + 2 * (d[4] + d[7] + d[6] + d[5]);
3701 m[2] = 4 * d[8] + 2 * (-d[1] - d[3] - d[0] - d[2]) + d[4] + d[7] + d[6] + d[5];
3702 m[3] = d[1] - d[0] + d[4] - d[7] - d[6] + d[5];
3703 m[4] = -2 * (d[1] - d[0]) + d[4] - d[7] - d[6] + d[5];
3704 m[5] = d[3] - d[2] + d[4] + d[7] - d[6] - d[5];
3705 m[6] = -2 * (d[3] - d[2]) + d[4] + d[7] - d[6] - d[5];
3706 m[7] = d[1] - d[3] + d[0] - d[2];
3707 m[8] = d[4] - d[7] + d[6] - d[5];
3708
3709 // Relaxation in moment space
3710 // 1. Set relaxation parameters
3711 std::array<MFloat, nDist> omega{};
3712 omega[0] = 0.0;
3713 omega[1] = 1.63;
3714 omega[2] = 1.14;
3715 omega[3] = 0.0;
3716 omega[5] = 0.0;
3717 omega[6] = 1.92;
3718 omega[7] = (2.0 - c1) / (12.0 * a_nu(pCellId) * FFPOW2(lvlDiff) + 1.0 - c1 / 2.0);
3719 omega[8] = 1.0 / ((2.0 / omega[7] - 1.0) * ((c1 + 4.0) / (2.0 - c1)) + 0.5);
3720 omega[4] = 3.0 * (2.0 - omega[7]) / (3.0 - omega[7]);
3721
3722 // 2. Calculate equilibrium Moments
3723 std::array<MFloat, nDist> EqM{};
3724 EqM[0] = m[0];
3725 EqM[3] = m[3];
3726 EqM[5] = m[5];
3727 EqM[1] = 0.25 * alpha2 * m[0] + F1B6 * gamma2 * (m[3] * m[3] + m[5] * m[5]);
3728 EqM[2] = 0.25 * alpha3 * m[0] + F1B6 * gamma4 * (m[3] * m[3] + m[5] * m[5]);
3729 EqM[4] = 0.5 * c1 * m[3];
3730 EqM[6] = 0.5 * c1 * m[5];
3731 EqM[7] = F3B2 * gamma1 * (m[3] * m[3] - m[5] * m[5]);
3732 EqM[8] = F3B2 * gamma3 * (m[3] * m[5]);
3733
3734 // 3. Relax Moments
3735 for(MInt j = 0; j < nDist; j++) {
3736 m[j] = m[j] - omega[j] * (m[j] - EqM[j]);
3737 }
3738
3739 a_distribution(pCellId, 8) = F1B9 * m[0] - F1B9 * m[1] + F1B9 * m[2];
3740 a_distribution(pCellId, 1) = F1B9 * m[0] - F1B36 * m[1] - F1B18 * m[2] + F1B6 * m[3] - F1B6 * m[4] + F1B4 * m[7];
3741 a_distribution(pCellId, 3) = F1B9 * m[0] - F1B36 * m[1] - F1B18 * m[2] + F1B6 * m[5] - F1B6 * m[6] - F1B4 * m[7];
3742 a_distribution(pCellId, 0) = F1B9 * m[0] - F1B36 * m[1] - F1B18 * m[2] - F1B6 * m[3] + F1B6 * m[4] + F1B4 * m[7];
3743 a_distribution(pCellId, 2) = F1B9 * m[0] - F1B36 * m[1] - F1B18 * m[2] - F1B6 * m[5] + F1B6 * m[6] - F1B4 * m[7];
3744 a_distribution(pCellId, 4) = F1B9 * m[0] + F1B18 * m[1] + F1B36 * m[2] + F1B6 * m[3] + F1B12 * m[4] + F1B6 * m[5]
3745 + F1B12 * m[6] + F1B4 * m[8];
3746 a_distribution(pCellId, 7) = F1B9 * m[0] + F1B18 * m[1] + F1B36 * m[2] - F1B6 * m[3] - F1B12 * m[4] + F1B6 * m[5]
3747 + F1B12 * m[6] - F1B4 * m[8];
3748 a_distribution(pCellId, 6) = F1B9 * m[0] + F1B18 * m[1] + F1B36 * m[2] - F1B6 * m[3] - F1B12 * m[4] - F1B6 * m[5]
3749 - F1B12 * m[6] + F1B4 * m[8];
3750 a_distribution(pCellId, 5) = F1B9 * m[0] + F1B18 * m[1] + F1B36 * m[2] + F1B6 * m[3] + F1B12 * m[4] - F1B6 * m[5]
3751 - F1B12 * m[6] - F1B4 * m[8];
3752 }
3753 }
3754}
3755
3756template <>
3757template <MBool optimized, MBool useSmagorinsky>
3759 TRACE();
3760 constexpr MInt nDist = 19;
3761 constexpr MInt nDim = 3;
3762 constexpr MInt nDimSqr = nDim * nDim;
3763
3764 const MFloat rho_offset = (m_densityFluctuations) ? 1.0 : 0.0;
3765
3766 // Only relevant for Smagorinsky model
3767 [[maybe_unused]] const MFloat tmpWidth = m_referenceLength * m_smallestCellLength;
3768 [[maybe_unused]] constexpr MFloat aPlus = 26.0;
3769
3770 for(MInt id = 0; id < m_currentMaxNoCells; id++) {
3771 const MInt pCellId = m_activeCellList[id];
3772
3773 if((globalTimeStep - 1) % IPOW2(maxLevel() - this->a_level(pCellId)) == 0) {
3774 m_nu = m_Ma * LBCS / m_Re * m_referenceLength;
3775
3776 MFloat d[nDist];
3777 for(MInt j = 0; j < nDist; j++) {
3778 d[j] = a_oldDistribution(pCellId, j);
3779 }
3780
3781 // Set old variables (for residual calculation)
3782 for(MInt j = 0; j < nDim + 1; j++) {
3783 a_oldVariable(pCellId, j) = a_variable(pCellId, j);
3784 }
3785
3786 MFloat m[nDist];
3787 m[0] = d[18] + d[1] + d[0] + d[3] + d[2] + d[5] + d[4] + d[9] + d[7] + d[8] + d[6] + d[13] + d[11] + d[12] + d[10]
3788 + d[17] + d[15] + d[16] + d[14];
3789 m[1] = -30 * d[18] - 11 * (d[1] + d[0] + d[3] + d[2] + d[5] + d[4])
3790 + 8 * (d[9] + d[7] + d[8] + d[6] + d[13] + d[11] + d[12] + d[10] + d[17] + d[15] + d[16] + d[14]);
3791 m[2] = 12 * d[18] - 4 * (d[1] + d[0] + d[3] + d[2] + d[5] + d[4]) + d[9] + d[7] + d[8] + d[6] + d[13] + d[11]
3792 + d[12] + d[10] + d[17] + d[15] + d[16] + d[14];
3793 m[3] = d[1] - d[0] + d[9] - d[7] + d[8] - d[6] + d[13] - d[11] + d[12] - d[10];
3794 m[4] = -4 * (d[1] - d[0]) + d[9] - d[7] + d[8] - d[6] + d[13] - d[11] + d[12] - d[10];
3795 m[5] = d[3] - d[2] + d[9] + d[7] - d[8] - d[6] + d[17] - d[15] + d[16] - d[14];
3796 m[6] = -4 * (d[3] - d[2]) + d[9] + d[7] - d[8] - d[6] + d[17] - d[15] + d[16] - d[14];
3797 m[7] = d[5] - d[4] + d[13] + d[11] - d[12] - d[10] + d[17] + d[15] - d[16] - d[14];
3798 m[8] = -4 * (d[5] - d[4]) + d[13] + d[11] - d[12] - d[10] + d[17] + d[15] - d[16] - d[14];
3799 m[9] = 2 * (d[1] + d[0] - d[15] - d[16] - d[14]) - d[3] - d[2] - d[5] - d[4] + d[9] + d[7] + d[8] + d[6] + d[13]
3800 + d[11] + d[12] + d[10] - 2 * d[17];
3801 m[10] = -4 * (d[1] + d[0]) + 2 * (d[3] + d[2] + d[5] + d[4] - d[17] - d[15] - d[16] - d[14]) + d[9] + d[7] + d[8]
3802 + d[6] + d[13] + d[11] + d[12] + d[10];
3803 m[11] = d[3] + d[2] - d[5] - d[4] + d[9] + d[7] + d[8] + d[6] - d[13] - d[11] - d[12] - d[10];
3804 m[12] = -2 * (d[3] + d[2] - d[5] - d[4]) + d[9] + d[7] + d[8] + d[6] - d[13] - d[11] - d[12] - d[10];
3805 m[13] = d[9] - d[7] - d[8] + d[6];
3806 m[14] = d[17] - d[15] - d[16] + d[14];
3807 m[15] = d[13] - d[11] - d[12] + d[10];
3808 m[16] = d[9] - d[7] + d[8] - d[6] - d[13] + d[11] - d[12] + d[10];
3809 m[17] = -d[9] - d[7] + d[8] + d[6] + d[17] - d[15] + d[16] - d[14];
3810 m[18] = d[13] + d[11] - d[12] - d[10] - d[17] - d[15] + d[16] + d[14];
3811
3812 // Relaxation in moment space
3813 // 1. Set relaxation parameters
3814 MFloat P[nDist];
3815 const MFloat tmp = (optimized) ? 0.0 : 1.0;
3816 P[0] = tmp;
3817 P[1] = 1.19;
3818 P[2] = 1.4;
3819 P[3] = tmp;
3820 P[4] = 1.2;
3821 P[5] = tmp;
3822 P[6] = P[4];
3823 P[7] = tmp;
3824 P[8] = P[4];
3825 P[9] = 2.0 / (FFPOW2(maxLevel() - this->a_level(pCellId)) * 6.0 * m_nu + 1.0);
3826 P[10] = P[2];
3827 P[11] = P[9];
3828 P[12] = P[2];
3829 P[13] = P[9];
3830 P[14] = P[9];
3831 P[15] = P[9];
3832 P[16] = 1.98;
3833 P[17] = P[16];
3834 P[18] = P[16];
3835
3836 // 2. Calculate equilibrium Moments
3837 MFloat EqM[nDist];
3838 EqM[0] = m[0]; // rho
3839 EqM[3] = m[3]; // j_x
3840 EqM[5] = m[5]; // j_y
3841 EqM[7] = m[7]; // j_z
3842
3843 //---------------------------------------------------------------------------------
3844 // d'Humieres et al., 2002 (standard/optimized parameters)
3845 // compressible form
3846 EqM[1] = -11.0 * m[0] + 19.0 * (m[3] * m[3] + m[5] * m[5] + m[7] * m[7]) / (m[0] + rho_offset); // e
3847
3848 if constexpr(optimized) {
3849 EqM[2] = -F475B63 * (m[3] * m[3] + m[5] * m[5] + m[7] * m[7]) / (m[0] + rho_offset); // epsilon
3850 } else {
3851 EqM[2] = 3.0 * m[0] - 5.5 * (m[3] * m[3] + m[5] * m[5] + m[7] * m[7]) / (m[0] + rho_offset); // epsilon
3852 }
3853
3854 EqM[4] = -F2B3 * m[3]; // q_x
3855 EqM[6] = -F2B3 * m[5]; // q_y
3856 EqM[8] = -F2B3 * m[7]; // q_z
3857
3858 EqM[9] = (2 * m[3] * m[3] - (m[5] * m[5] + m[7] * m[7])) / (m[0] + rho_offset); // 3*p_xx
3859
3860 if constexpr(optimized) {
3861 EqM[10] = 0.0;
3862 } else {
3863 EqM[10] = -0.5 * EqM[9]; // 3*pi_xx
3864 }
3865 EqM[11] = (m[5] * m[5] - m[7] * m[7]) / (m[0] + rho_offset); // p_ww
3866 if constexpr(optimized) {
3867 EqM[12] = 0.0;
3868 } else {
3869 EqM[12] = -0.5 * EqM[11]; // pi_ww
3870 }
3871 EqM[13] = m[3] * m[5] / (m[0] + rho_offset); // p_xy
3872 EqM[14] = m[5] * m[7] / (m[0] + rho_offset); // p_yz
3873 EqM[15] = m[3] * m[7] / (m[0] + rho_offset); // p_xz
3874 EqM[16] = 0;
3875 EqM[17] = 0;
3876 EqM[18] = 0;
3877
3878 // // incompressible form assuming <rho> = 1
3879 // EqM[1] = -11.0 * m[0] + 19.0 * ( m[3] * m[3] + m[5] * m[5] + m[7] * m[7] ); // e
3880
3881 // EqM[2] = 3.0 * m[0] - 5.5 * ( m[3] * m[3] + m[5] * m[5] + m[7] * m[7] ); // epsilon
3882
3883 // EqM[4] = -F2B3 * m[3] ; // q_x
3884 // EqM[6] = -F2B3 * m[5] ; // q_y
3885 // EqM[8] = -F2B3 * m[7] ; // q_z
3886
3887 // EqM[9] = ( 2*m[3]*m[3] - (m[5] * m[5] + m[7] * m[7]) ); // 3*p_xx
3888
3889 // EqM[10] = -0.5 * EqM[9] ; // 3*pi_xx
3890 // EqM[11] = ( m[5] * m[5] - m[7] * m[7] ); // p_ww
3891 // EqM[12] = -0.5 * EqM[11] ; // pi_ww
3892 // EqM[13] = m[3] * m[5]; // p_xy
3893 // EqM[14] = m[5] * m[7]; // p_yz
3894 // EqM[15] = m[3] * m[7]; // p_xz
3895 // EqM[16] = 0 ;
3896 // EqM[17] = 0 ;
3897 // EqM[18] = 0 ;
3898
3899 //---------------------------------------------------------------------------------
3900
3901 // 2b. Determine macroscopic variables and calculate residual
3902 a_variable(pCellId, PV->RHO) = EqM[0];
3903 for(MInt i = 0; i < nDim; i++) {
3904 a_variable(pCellId, PV->VV[i]) = EqM[3 + i * 2] / EqM[0];
3905 }
3906
3907 // 2c. Smagorinsky model
3908 if constexpr(useSmagorinsky) {
3909 // Calculation of equilibrium and non-equilibrium distribution
3910 MFloat nonEq[nDist];
3911#ifdef WAR_NVHPC_PSTL
3912 MFloat dist[nDist] = {F0};
3913 MFloat u[nDim] = {F0};
3914 for(MInt dir = 0; dir < nDist; dir++) {
3915 dist[dir] = a_oldDistribution(pCellId, dir);
3916 }
3917 for(MInt dir = 0; dir < nDim; dir++) {
3918 u[dir] = a_variable(pCellId, dir);
3919 }
3920 MFloat l_rho = a_variable(pCellId, PV->RHO);
3921 lbfunc::calcNonEqDists<nDim, nDist>(l_rho, u, dist, &nonEq[0]);
3922#else
3923 lbfunc::calcNonEqDists<nDim, nDist>(a_variable(pCellId, PV->RHO), &a_variable(pCellId, PV->U),
3924 &a_oldDistribution(pCellId, 0), &nonEq[0]);
3925#endif
3926
3927 // Smagorinsky model
3928 const MFloat yPlus = m_ReTau * (1.0 - fabs(a_coordinate(pCellId, 1)) / tmpWidth);
3929 const MFloat lambda = m_Cs * m_deltaX * (F1 - exp(-yPlus / aPlus));
3930
3931 // Calculation of momentum flux tensor from non-equilibrium parts
3932 MFloat c[nDimSqr];
3933 c[0] = (nonEq[0] + nonEq[1] + nonEq[6] + nonEq[7] + nonEq[8] + nonEq[9] + nonEq[10] + nonEq[11] + nonEq[12]
3934 + nonEq[13]);
3935 c[1] = (nonEq[6] - nonEq[7] - nonEq[8] + nonEq[9]);
3936 c[2] = (nonEq[10] - nonEq[11] - nonEq[12] + nonEq[13]);
3937 c[3] = c[1];
3938 c[4] = (nonEq[2] + nonEq[3] + nonEq[6] + nonEq[7] + nonEq[8] + nonEq[9] + nonEq[14] + nonEq[15] + nonEq[16]
3939 + nonEq[17]);
3940 c[5] = (nonEq[14] - nonEq[15] - nonEq[16] + nonEq[17]);
3941 c[6] = c[2];
3942 c[7] = c[5];
3943 c[8] = (nonEq[4] + nonEq[5] + nonEq[10] + nonEq[11] + nonEq[12] + nonEq[13] + nonEq[14] + nonEq[15] + nonEq[16]
3944 + nonEq[17]);
3945
3946 // Calculation of the filtered mean momentum flux
3947 const MFloat Q = sqrt(2.0 * std::inner_product(&c[0], &c[nDimSqr], &c[0], .0));
3948
3949 // Calculation of new relaxation time
3950 // ..original relaxation time (on current level)
3951 MFloat tau = F1B2 + 3.0 * m_nu * FFPOW2(maxLevel() - this->a_level(pCellId));
3952 // ..new
3953 tau += F1B2
3954 * (sqrt(tau * tau
3955 + 2.0 * SQRT2 * lambda * lambda * (F1BCSsq * F1BCSsq) * Q
3956 * FPOW2(maxLevel() - this->a_level(pCellId)))
3957 - tau);
3958
3959 m_omega = 1.0 / tau;
3960
3961 // save total nu for bndcnd and interface interpolation (save on finest level)
3962 a_nu(pCellId) = FPOW2(maxLevel() - this->a_level(pCellId)) * (tau - F1B2) / 3.0;
3963
3964 // set new relaxation time
3965 P[9] = m_omega;
3966 }
3967
3968 // 3. Relax Moments
3969 for(MInt i = 0; i < nDist; i++) {
3970 m[i] = m[i] - P[i] * (m[i] - EqM[i]);
3971 }
3972
3973 const MFloat ra = F1B19 * m[0];
3974 const MFloat rb = F11B2394 * m[1];
3975 const MFloat rc = F1B63 * m[2];
3976 const MFloat rd = F4B1197 * m[1];
3977 const MFloat re = F1B252 * m[2];
3978 const MFloat rf = F1B12 * m[11];
3979 const MFloat rg = F1B24 * m[12];
3980 const MFloat rh = 0.25 * m[13];
3981 const MFloat ri = 0.25 * m[15];
3982 const MFloat rj = F1B36 * m[9];
3983 const MFloat rk = 2.0 * rj;
3984 const MFloat rl = F1B72 * m[10];
3985 const MFloat rm = 2.0 * rl;
3986 const MFloat rn = 0.1 * (m[3] - m[4]);
3987 const MFloat ro = 0.1 * (m[5] - m[6]);
3988 const MFloat rp = 0.1 * (m[7] - m[8]);
3989 const MFloat rq = F1B18 * (m[9] - m[10]);
3990 const MFloat rr = F1B12 * (m[11] - m[12]);
3991 const MFloat rs = 0.25e-1 * (m[4] + m[6]);
3992 const MFloat rt = 0.25e-1 * (m[4] - m[6]);
3993 const MFloat ru = 0.25e-1 * (m[4] - m[8]);
3994 const MFloat rv = 0.25e-1 * (m[4] + m[8]);
3995 const MFloat rw = 0.25e-1 * (m[6] + m[8]);
3996 const MFloat rx = 0.25e-1 * (m[6] - m[8]);
3997 const MFloat ry = 0.125 * (m[16] - m[17]);
3998 const MFloat rz = 0.125 * (m[16] + m[17]);
3999 const MFloat r0 = 0.125 * (m[16] - m[18]);
4000 const MFloat r1 = 0.125 * (m[16] + m[18]);
4001 const MFloat r2 = 0.125 * (m[17] + m[18]);
4002 const MFloat r3 = 0.125 * (m[17] - m[18]);
4003 const MFloat r4 = 0.1 * (m[5] + m[7]);
4004 const MFloat r5 = 0.1 * (m[5] - m[7]);
4005 const MFloat r6 = 0.1 * (m[3] + m[5]);
4006 const MFloat r7 = 0.1 * (m[3] - m[5]);
4007 const MFloat r8 = 0.5 * rq;
4008 const MFloat r9 = 0.1 * (m[3] + m[7]);
4009 const MFloat r10 = 0.1 * (m[3] - m[7]);
4010 const MFloat r11 = 0.25 * m[14];
4011
4012 // ra = 0.5263157895e-1*m[0];
4013 // rb = 0.4594820384e-2*m[1];
4014 // rc = 0.1587301587e-1*m[2];
4015 // rd = 0.3341687552e-2*m[1];
4016 // re = 0.3968253968e-2*m[2];
4017 // rf = 0.8333333333e-1*m[11];
4018 // rg = 0.4166666667e-1*m[12];
4019 // rh = 0.250*m[13];
4020 // ri = 0.250*m[15];
4021 // rj = 0.2777777778e-1*m[9];
4022 // rk = 2*rj;
4023 // rl = 0.1388888889e-1*m[10];
4024 // rm = 2*rl;
4025 // rn = 0.10*(m[3]-m[4]);
4026 // ro = 0.10*(m[5]-m[6]);
4027 // rp = 0.10*(m[7]-m[8]);
4028 // rq = 0.5555555556e-1*(m[9]-m[10]);
4029 // rr = 0.8333333333e-1*(m[11]-m[12]);
4030 // rs = 0.250e-1*(m[4]+m[6]);
4031 // rt = 0.250e-1*(m[4]-m[6]);
4032 // ru = 0.250e-1*(m[4]-m[8]);
4033 // rv = 0.250e-1*(m[4]+m[8]);
4034 // rw = 0.250e-1*(m[6]+m[8]);
4035 // rx = 0.250e-1*(m[6]-m[8]);
4036 // ry = 0.1250*(m[16]-m[17]);
4037 // rz = 0.1250*(m[16]+m[17]);
4038 // r0 = 0.1250*(m[16]-m[18]);
4039 // r1 = 0.1250*(m[16]+m[18]);
4040 // r2 = 0.1250*(m[17]+m[18]);
4041 // r3 = 0.1250*(m[17]-m[18]);
4042 // r4 = 0.10*(m[5]+m[7]);
4043 // r5 = 0.10*(m[5]-m[7]);
4044 // r6 = 0.10*(m[3]+m[5]);
4045 // r7 = 0.10*(m[3]-m[5]);
4046 // r8 = 0.5*rq;
4047 // r9 = 0.10*(m[3]+m[7]);
4048 // r10= 0.10*(m[3]-m[7]);
4049 // r11= 0.250*m[14];
4050
4051 a_distribution(pCellId, 18) = ra - F5B399 * m[1] + F1B21 * m[2];
4052 a_distribution(pCellId, 1) = ra - rb - rc + rn + rq;
4053 a_distribution(pCellId, 0) = ra - rb - rc - rn + rq;
4054 a_distribution(pCellId, 3) = ra - rb - rc + ro - r8 + rr;
4055 a_distribution(pCellId, 2) = ra - rb - rc - ro - r8 + rr;
4056 a_distribution(pCellId, 5) = ra - rb - rc + rp - r8 - rr;
4057 a_distribution(pCellId, 4) = ra - rb - rc - rp - r8 - rr;
4058 a_distribution(pCellId, 9) = ra + rd + re + r6 + rs + rj + rl + rf + rg + rh + ry;
4059 a_distribution(pCellId, 7) = ra + rd + re - r7 - rt + rj + rl + rf + rg - rh - rz;
4060 a_distribution(pCellId, 8) = ra + rd + re + r7 + rt + rj + rl + rf + rg - rh + rz;
4061 a_distribution(pCellId, 6) = ra + rd + re - r6 - rs + rj + rl + rf + rg + rh - ry;
4062 a_distribution(pCellId, 13) = ra + rd + re + r9 + rv + rj + rl - rf - rg + ri - r0;
4063 a_distribution(pCellId, 11) = ra + rd + re - r10 - ru + rj + rl - rf - rg - ri + r1;
4064 a_distribution(pCellId, 12) = ra + rd + re + r10 + ru + rj + rl - rf - rg - ri - r1;
4065 a_distribution(pCellId, 10) = ra + rd + re - r9 - rv + rj + rl - rf - rg + ri + r0;
4066 a_distribution(pCellId, 17) = ra + rd + re + r4 + rw - rk - rm + r11 + r3;
4067 a_distribution(pCellId, 15) = ra + rd + re - r5 - rx - rk - rm - r11 - r2;
4068 a_distribution(pCellId, 16) = ra + rd + re + r5 + rx - rk - rm - r11 + r2;
4069 a_distribution(pCellId, 14) = ra + rd + re - r4 - rw - rk - rm + r11 - r3;
4070 }
4071 }
4072
4073 if(m_calculateDissipation && globalTimeStep % m_solutionInterval == 0) {
4074 calculateDissipation();
4075 }
4076}
4077
4088template <MInt nDim, MInt nDist, class SysEqn>
4090 mrt_collision_step_base<false, false>();
4091}
4092
4103template <MInt nDim, MInt nDist, class SysEqn>
4105 mrt_collision_step_base<true, false>();
4106}
4107
4120template <MInt nDim, MInt nDist, class SysEqn>
4122 if constexpr(nDim == 3 || nDist == 19) {
4123 mrt_collision_step_base<false, true>();
4124 } else {
4125 TERMM(1, "MRT_SMAGORINSKY collision step only available for D3Q19!");
4126 }
4127}
4128
4129template <MInt nDim, MInt nDist, class SysEqn>
4130template <MBool useSmagorinsky>
4132 TRACE();
4133
4134 if(m_tanhInit && (globalTimeStep > m_initStartTime)) {
4135 MFloat scale =
4136 0.5 * (m_tanhScaleFactor * tanh((5.0 * (MFloat)(globalTimeStep - m_initStartTime) / (MFloat)m_initTime) - 2.5))
4137 + 0.5;
4138
4139 m_Re = m_initRe + scale * (m_finalRe - m_initRe);
4140
4141 // final timestep reached
4142 if(globalTimeStep == m_initStartTime + m_initTime) {
4143 m_Re = m_finalRe;
4144 m_tanhInit = 0;
4145 }
4146 }
4147 m_nu = m_Ma * LBCS / m_Re * m_referenceLength;
4148
4149 for(MInt i = 0; i < m_currentMaxNoCells; i++) {
4150 const MInt pCellId = m_activeCellList[i];
4151
4152 if((globalTimeStep - 1) % IPOW2(maxLevel() - this->a_level(pCellId)) == 0) {
4153 // save nu for bndcnd and interface interpolation
4154 a_nu(pCellId) = m_nu;
4155
4156 m_omega = 2.0 / (1.0 + 6.0 * m_nu * FFPOW2(maxLevel() - this->a_level(pCellId)));
4157 swap_variables(pCellId);
4158
4159 // Calculate macroscopic variables
4160 a_variable(pCellId, PV->RHO) = 0.0;
4161 for(MInt j = 0; j < nDist; j++) {
4162 a_variable(pCellId, PV->RHO) += a_oldDistribution(pCellId, j);
4163 }
4164
4165 const MFloat rho = a_variable(pCellId, PV->RHO);
4166
4167 MFloat u[nDim];
4168 for(MInt j = 0; j < nDim; j++) {
4169 u[j] = F0;
4170 }
4171
4172 if constexpr(nDim == 2) {
4173 // warning!!! the velocity should be calculated as in 3d
4174 // however, result is correct
4175 // calculation of u
4176 u[0] = a_oldDistribution(pCellId, 1) + a_oldDistribution(pCellId, 4) + a_oldDistribution(pCellId, 5)
4177 - a_oldDistribution(pCellId, 7) - a_oldDistribution(pCellId, 6) - a_oldDistribution(pCellId, 0);
4178 // calculation of v
4179 u[1] = a_oldDistribution(pCellId, 7) + a_oldDistribution(pCellId, 3) + a_oldDistribution(pCellId, 4)
4180 - a_oldDistribution(pCellId, 6) - a_oldDistribution(pCellId, 2) - a_oldDistribution(pCellId, 5);
4181 } else {
4182 for(MInt j = 0; j < Ld::dxQyFld(); j++) {
4183 for(MInt d = 0; d < nDim; d++) {
4184 u[d] += a_oldDistribution(pCellId, Ld::pFld(d, j));
4185 u[d] -= a_oldDistribution(pCellId, Ld::nFld(d, j));
4186 }
4187 }
4188 }
4189
4190 for(MInt j = 0; j < nDim; j++) {
4191 a_variable(pCellId, j) = u[j];
4192 }
4193
4194 // Calculation of equilibrium and non-equilibrium distribution
4195 std::array<MFloat, nDist> eqDist;
4196 eqDist = getEqDists(rho, u);
4197
4198 // Calculation of momentum flux tensor for non-equilibrium parts
4199 //--------------------------------------------
4200 // \Pi_{\alpha,\beta} = \sum_i f_i \cdot c_{i,\alpha}c_{i,\beta}
4201
4202 calculateMomentumFlux(pCellId);
4203
4204 if constexpr(useSmagorinsky) {
4205 // Calculation of overall viscosity
4206 // according to Hu, Sterling, Chen 1994
4207
4208 // 1. Calculation of original relaxation time (on current level)
4209 MFloat tau = F1B2 + 3.0 * m_nu * FFPOW2(maxLevel() - this->a_level(pCellId));
4210
4211 // 2. Calculation of the filtered mean momentum flux
4212 MFloat Q = F0;
4213 for(MInt l = 0; l < nDim * nDim; l++) {
4214 Q += m_momentumFlux[pCellId][l] * m_momentumFlux[pCellId][l];
4215 }
4216 Q = sqrt(2 * Q);
4217
4218 // 3. Calculation of new relaxation time
4219 tau += F1B2
4220 * (sqrt(tau * tau
4221 + 2.0 * SQRT2 * m_Cs * m_Cs * m_deltaX * m_deltaX * (F1BCSsq * F1BCSsq) * Q
4222 * FPOW2(maxLevel() - this->a_level(pCellId)))
4223 - tau);
4224
4225 m_omega = 1.0 / tau;
4226
4227 // save total nu for bndcnd and interface interpolation (save on finest level)
4228 a_nu(pCellId) = FPOW2(maxLevel() - this->a_level(pCellId)) * (tau - F1B2) / 3.0;
4229 }
4230
4231 // Calculation of new distributions for directions with at least one component
4232 MFloat trace = F0;
4233
4234 if constexpr(nDim == 2) {
4235 trace = m_momentumFlux[pCellId][0] + m_momentumFlux[pCellId][3];
4236 } else {
4237 trace = m_momentumFlux[pCellId][0] + m_momentumFlux[pCellId][4] + m_momentumFlux[pCellId][8];
4238 }
4239
4240 for(MInt j = 0; j < nDist - 1; j++) {
4241 const MInt t = Ld::tp(Ld::distType(j));
4242
4243 a_distribution(pCellId, j) = eqDist[j] - (1.0 - m_omega) * t * F1BCSsq * F1B2 * trace;
4244
4245 for(MInt k = 0; k < nDim; k++) {
4246 for(MInt l = 0; l < nDim; l++) {
4247 a_distribution(pCellId, j) += (1.0 - m_omega) * t * F1BCSsq * F1BCSsq * F1B2 * (Ld::idFld(j, k) - 1)
4248 * (Ld::idFld(j, l) - 1) * m_momentumFlux[pCellId][l + nDim * k];
4249 }
4250 }
4251 }
4252 // Calculation of new distribution for rest particle distribution (center)
4253 a_distribution(pCellId, Ld::lastId()) =
4254 eqDist[Ld::lastId()] - (1.0 - m_omega) * Ld::tp(0) * F1BCSsq * F1B2 * trace;
4255 }
4256 }
4257
4258 if(m_calculateDissipation && globalTimeStep % m_solutionInterval == 0) {
4259 calculateDissipation();
4260 }
4261}
4262
4269template <MInt nDim, MInt nDist, class SysEqn>
4271 rbgk_collision_step_base<false>();
4272}
4273
4280template <MInt nDim, MInt nDist, class SysEqn>
4282 rbgk_collision_step_base<true>();
4283}
4284
4291template <MInt nDim, MInt nDist, class SysEqn>
4293 TRACE();
4294
4295 updateMacroscopicVariables();
4296 for(MInt i = 0; i < this->noInternalCells(); i++) {
4297 calculateMomentumFlux(i);
4298 }
4299 calculateSGSTensors();
4300
4301 std::vector<MFloat> dynamicCs;
4302 constexpr MInt direction = 1;
4303 MInt count = 0;
4304 averageSGSTensors(direction, count, dynamicCs);
4305
4306 for(MInt i = 0; i < count; i++) {
4307 if(dynamicCs[i] < 0.0) dynamicCs[i] = 0.0;
4308 // if(dynamicCs[i]>0.04)
4309 // dynamicCs[i] = 0.04;
4310 }
4311
4312 MFloat rho = F0;
4313 MFloat u[nDim];
4314 MFloat Q = F0;
4315 MFloat tau = F0;
4316 MFloat S = F0;
4317
4318 MInt index = 0;
4319 MFloat actualCellLength = F0;
4320
4321 MChar buf[10];
4322 MString fileName;
4323 ofstream ofl;
4324
4325 // dissipation values
4326 ScratchSpace<MFloat> diss(m_arraySize[direction], AT_, "diss");
4327 ScratchSpace<MFloat> totalDiss(m_arraySize[direction], AT_, "totalDiss");
4328 ScratchSpace<MFloat> SGSDiss(m_arraySize[direction], AT_, "SGSDiss");
4329 ScratchSpace<MFloat> totalSGSDiss(m_arraySize[direction], AT_, "totalSGSDiss");
4330 MFloat energy;
4331
4332 // reset dissipation and energy values
4333 for(MInt i = 0; i < count; i++) {
4334 diss[i] = F0;
4335 SGSDiss[i] = F0;
4336 }
4337 energy = F0;
4338
4339 if(m_tanhInit && (globalTimeStep > m_initStartTime)) {
4340 MFloat scale =
4341 0.5 * (m_tanhScaleFactor * tanh((5.0 * (MFloat)(globalTimeStep - m_initStartTime) / (MFloat)m_initTime) - 2.5))
4342 + 0.5;
4343
4344 m_Re = m_initRe + scale * (m_finalRe - m_initRe);
4345
4346 // final timestep reached
4347 if(globalTimeStep == m_initStartTime + m_initTime) {
4348 m_Re = m_finalRe;
4349 m_tanhInit = 0;
4350 }
4351 }
4352 m_nu = m_Ma * LBCS / m_Re * m_referenceLength;
4353
4354 for(MInt i = 0; i < m_currentMaxNoCells; i++) {
4355 const MInt pCellId = m_activeCellList[i];
4356
4357 if((globalTimeStep - 1) % IPOW2(maxLevel() - this->a_level(pCellId)) == 0) {
4358 rho = a_variable(pCellId, PV->RHO);
4359
4360 for(MInt d = 0; d < nDim; d++) {
4361 u[d] = a_variable(pCellId, d);
4362 }
4363
4364 // Calculation of equilibrium and non-equilibrium distribution
4365 std::array<MFloat, nDist> eqDist;
4366 eqDist = getEqDists(rho, u);
4367
4368 //--------------------------------------------
4369 // Calculation of overall viscosity
4370 // according to Hu, Sterling, Chen 1994
4371
4372 // 1. Calculation of original relaxation time (on current level)
4373 tau = F1B2 + 3.0 * m_nu * FFPOW2(maxLevel() - this->a_level(pCellId));
4374
4375 // 2. Calculation of the filtered mean momentum flux
4376 Q = 0.0;
4377 for(MInt k = 0; k < nDim * nDim; k++) {
4378 Q += m_momentumFlux[pCellId][k] * m_momentumFlux[pCellId][k];
4379 }
4380 Q = sqrt(2.0 * Q);
4381
4382 // 3. Calculation of new relaxation time
4383 // index = (MInt)((a_coordinate(pCellId, direction) - minCoord) / length * MFloat(count - 1) + 0.5);
4384 index = floor(
4385 (F1B2 * count
4386 + (a_coordinate(pCellId, direction) - F1B2 * (actualCellLength)) / (this->c_cellLengthAtLevel(maxLevel())))
4387 + 0.1);
4388
4389 tau += F1B2
4390 * (sqrt(tau * tau
4391 + 2.0 * SQRT2 * dynamicCs[index] * m_deltaX * m_deltaX * (F1BCSsq * F1BCSsq) * Q
4392 * FPOW2(maxLevel() - this->a_level(pCellId)))
4393 - tau);
4394
4395 m_omega = 1.0 / tau;
4396
4397 // save total nu for bndcnd and interface interpolation (save on finest level)
4398 a_nu(pCellId) = FPOW2(maxLevel() - this->a_level(pCellId)) * (tau - F1B2) / 3.0;
4399
4400 //--------------------------------------------
4401
4402 // Calculation of new distributions for directions with at least one component
4403 MFloat trace = F0;
4404
4405 if constexpr(nDim == 2) {
4406 trace = m_momentumFlux[pCellId][0] + m_momentumFlux[pCellId][3];
4407 } else {
4408 trace = m_momentumFlux[pCellId][0] + m_momentumFlux[pCellId][4] + m_momentumFlux[pCellId][8];
4409 }
4410
4411 for(MInt j = 0; j < (nDist - 1); j++) {
4412 MFloat t = F0;
4413 if(j < Ld::distFld(0)) {
4414 t = Ld::tp(1);
4415 } else if(j < Ld::distFld(1) + Ld::distFld(0)) {
4416 t = Ld::tp(2);
4417 } else {
4418 t = Ld::tp(3);
4419 }
4420
4421 a_distribution(pCellId, j) = eqDist[j] - (1.0 - m_omega) * t * F1BCSsq * F1B2 * trace;
4422
4423 for(MInt k = 0; k < nDim; k++) {
4424 for(MInt l = 0; l < nDim; l++) {
4425 a_distribution(pCellId, j) += (1.0 - m_omega) * t * F1BCSsq * F1BCSsq * F1B2 * (Ld::idFld(j, k) - 1)
4426 * (Ld::idFld(j, l) - 1) * m_momentumFlux[pCellId][l + nDim * k];
4427 }
4428 }
4429 }
4430 // Calculation of new distribution for rest particle distribution (center)
4431 a_distribution(pCellId, Ld::lastId()) =
4432 eqDist[Ld::lastId()] - (1.0 - m_omega) * Ld::tp(0) * F1BCSsq * F1B2 * trace;
4433
4434 //---------------------------
4435 // save dissipation values
4436
4437 // Calculate characteristic filtered rate of strain using original viscosity
4438 m_omega = 2.0 / (1.0 + 6.0 * m_nu * FFPOW2(maxLevel() - this->a_level(pCellId)));
4439 S = -F1B2 * F1BCSsq * m_omega * Q;
4440
4441 // Calculate molecular- and subgrid dissipation
4442 diss[index] += m_nu * S * S;
4443 SGSDiss[index] += dynamicCs[index] * m_deltaX * m_deltaX * S * S * S * FPOW4(maxLevel() - this->a_level(pCellId));
4444 for(MInt d = 0; d < nDim; d++) {
4445 energy += F1B2 * (a_variable(pCellId, d) * a_variable(pCellId, d));
4446 }
4447 //---------------------------
4448 }
4449 }
4450
4451 // write dissipation values
4452 if(m_calculateDissipation && globalTimeStep % m_solutionInterval == 0) {
4453 // for (MInt i=0; i<count; i++){
4454 // m_log <<"cs["<<i<<"]="<<dynamicCs[i]<<endl;
4455 // }
4456
4457 // all domains send their information to domain_0
4458 if(domainId() != 0) {
4459 MPI_Send(&(diss[0]), count, MPI_DOUBLE, 0, 0, mpiComm(), AT_, "(diss[0])");
4460 MPI_Send(&(SGSDiss[0]), count, MPI_DOUBLE, 0, 0, mpiComm(), AT_, "(SGSDiss[0])");
4461 MPI_Send(&energy, 1, MPI_DOUBLE, 0, 0, mpiComm(), AT_, "energy");
4462 }
4463
4464 if(domainId() == 0) {
4465 MPI_Status status;
4466
4467 for(MInt i = 0; i < count; i++) {
4468 totalDiss[i] = diss[i];
4469 totalSGSDiss[i] = SGSDiss[i];
4470 }
4471
4472 for(MInt j = 1; j < noDomains(); j++) {
4473 MPI_Recv(&(diss[0]), count, MPI_DOUBLE, j, 0, mpiComm(), &status, AT_, "(diss[0])");
4474 MPI_Recv(&(SGSDiss[0]), count, MPI_DOUBLE, j, 0, mpiComm(), &status, AT_, "(SGSDiss[0])");
4475 MPI_Recv(&energy, 1, MPI_DOUBLE, j, 0, mpiComm(), &status, AT_, "energy");
4476 for(MInt i = 0; i < count; i++) {
4477 totalDiss[i] += diss[i];
4478 totalSGSDiss[i] += SGSDiss[i];
4479 }
4480 }
4481
4482 fileName = "totalDiss_";
4483 sprintf(buf, "%d", globalTimeStep);
4484 fileName += buf;
4485 fileName += ".dat";
4486 m_log << "writing diss file: " << fileName << endl;
4487 ofl.open(fileName.c_str(), ios_base::out);
4488 for(MInt i = 0; i < count; i++)
4489 ofl << globalTimeStep << " " << i << " " << totalDiss[i] << " " << totalSGSDiss[i] << " " << energy << endl;
4490 ofl.close();
4491 }
4492 }
4493}
4494
4495
4504template <MInt nDim, MInt nDist, class SysEqn>
4506 TRACE();
4507
4508 // capable of D3Q19 and D3Q27
4509 for(MInt i = 0; i < m_currentMaxNoCells; i++) {
4510 const MInt pCellId = m_activeCellList[i];
4511
4512 if((globalTimeStep - 1) % IPOW2(maxLevel() - this->a_level(pCellId)) == 0) {
4513 m_nu = m_Ma * LBCS / m_Re * m_referenceLength;
4514
4515 m_omega = 2.0 / (1.0 + 6.0 * m_nu * FFPOW2(maxLevel() - this->a_level(pCellId)));
4516
4517 swap_variables(pCellId);
4518
4519 // Calculate macroscopic density
4520 a_variable(pCellId, PV->RHO) = 0.0;
4521 for(MInt j = 0; j < nDist; j++) {
4522 a_variable(pCellId, PV->RHO) += a_oldDistribution(pCellId, j);
4523 }
4524
4525 const MFloat rho = a_variable(pCellId, PV->RHO);
4526 MFloat u[nDim];
4527 for(MInt d = 0; d < nDim; d++) {
4528 u[d] = a_variable(pCellId, d);
4529 }
4530
4531 // Calculation of equilibrium and non-equilibrium distribution
4532 std::array<MFloat, nDist> eqDist;
4533 eqDist = getEqDists(rho, u);
4534
4535 // Calculation of momentum flux tensor for non-equilibrium parts
4536 //--------------------------------------------
4537 // \Pi_{\alpha,\beta} = \sum_i f_i \cdot c_{i,\alpha}c_{i,\beta}
4538 calculateMomentumFlux(pCellId);
4539
4540 // Calculation of new distributions for directions with at least one component
4541 MFloat trace = F0;
4542
4543 if constexpr(nDim == 2) {
4544 trace = m_momentumFlux[pCellId][0] + m_momentumFlux[pCellId][3];
4545 } else {
4546 trace = m_momentumFlux[pCellId][0] + m_momentumFlux[pCellId][4] + m_momentumFlux[pCellId][8];
4547 }
4548
4549 for(MInt j = 0; j < (nDist - 1); j++) {
4550 const MFloat t = Ld::tp(Ld::distType(j));
4551
4552 a_distribution(pCellId, j) = eqDist[j] - (1.0 - m_omega) * t * F1BCSsq * F1B2 * trace;
4553
4554 for(MInt k = 0; k < nDim; k++) {
4555 for(MInt l = 0; l < nDim; l++) {
4556 a_distribution(pCellId, j) += (1.0 - m_omega) * t * F1BCSsq * F1BCSsq * F1B2 * (Ld::idFld(j, k) - 1)
4557 * (Ld::idFld(j, l) - 1) * m_momentumFlux[pCellId][l + nDim * k];
4558 }
4559 }
4560 }
4561 // Calculation of new distribution for rest particle distribution (center)
4562 a_distribution(pCellId, Ld::lastId()) =
4563 eqDist[Ld::lastId()] - (1.0 - m_omega) * Ld::tp(0) * F1BCSsq * F1B2 * trace;
4564 }
4565 }
4566}
4567
4577template <MInt nDim, MInt nDist, class SysEqn>
4579 std::vector<MFloat>& meanTensors) {
4580 TRACE();
4581
4582 // MInt tmpId;
4583 // MInt saveId;
4584 // MInt tmpCt[3];
4585 // MFloat tmpMin[3];
4586 // MFloat tmpLength[3];
4587 //
4588 // /***********************************************/
4589 // /* Count all cells in x,y, and z-direction*/
4590 // for(MInt i=0; i < this->grid().noInternalCells(); i++){
4591 // // Ignore halo cells
4592 // if(cells[i].m_level < 0 )
4593 // continue;
4594 // if(this->c_noChildren(i)==0){
4595 // tmpId=i;
4596 // // Go to lowest level
4597 // while(c_parentId(tmpId) > -1){
4598 // tmpId=c_parentId(tmpId);
4599 // }
4600 // saveId = tmpId;
4601 // for(MInt j=0; j < 2*nDim; j+=2){
4602 // tmpId = saveId;
4603 // // Go to the last cell in current direction
4604 // while(a_hasNeighbor(tmpId, j)){
4605 // if( a_coordinate(c_neighborId(tmpId, j), j/2) < a_coordinate(tmpId, j/2) ){
4606 // tmpId=c_neighborId(tmpId, j);
4607 // }
4608 // else
4609 // break;
4610 // }
4611 //
4612 // tmpMin[j/2] = a_coordinate(tmpId, j/2);
4613 // tmpLength[j/2] = a_coordinate(tmpId, j/2);
4614 // // Go to the first cell in current direction
4615 // tmpCt[j/2] = 1;
4616 // while(a_hasNeighbor(tmpId, Ld::oppositeDist(j))){
4617 // if( a_coordinate(c_neighborId(tmpId, Ld::oppositeDist(j)), j/2) > a_coordinate(tmpId, j/2) ){
4618 // tmpId=c_neighborId(tmpId, Ld::oppositeDist(j));
4619 // tmpCt[j/2]++;
4620 // }
4621 // else
4622 // break;
4623 // }
4624 //
4625 // tmpLength[j/2] = (a_coordinate(tmpId, j/2) - tmpLength[j/2]);
4626 // }
4627 // }
4628 // break;
4629 // }
4630
4631 const MInt(&tmpCt)[nDim] = m_arraySize;
4632 count = tmpCt[direction];
4633
4634 ScratchSpace<MFloat> ML(tmpCt[direction], AT_, "ML");
4635 ScratchSpace<MFloat> MM(tmpCt[direction], AT_, "MM");
4636 meanTensors.resize(tmpCt[direction]);
4637
4638 for(MInt i = 0; i < tmpCt[direction]; i++) {
4639 MM[i] = F0;
4640 ML[i] = F0;
4641 meanTensors[i] = F0;
4642 }
4643
4644 // Sum up values
4645 for(MInt i = 0; i < this->grid().noInternalCells(); i++) {
4646 const MFloat actualCellLength = this->grid().cellLengthAtCell(i);
4647
4648 // const MInt index = (MInt)((a_coordinate(i, direction) - tmpMin[direction]) / (MFloat)tmpLength[direction]
4649 // * MFloat(tmpCt[direction] - 1) + 0.5);
4650
4651 const MInt index =
4652 floor((F1B2 * tmpCt[direction]
4653 + (a_coordinate(i, direction) - F1B2 * (actualCellLength)) / (this->c_cellLengthAtLevel(maxLevel())))
4654 + 0.1);
4655
4656 if(index < 0 || index >= tmpCt[direction]) {
4657 cerr << "error: index=" << index << endl;
4658 m_log << "error: index=" << index << endl;
4659 }
4660
4661 ML[index] += m_MijLij[i];
4662 MM[index] += m_MijMij[i];
4663 }
4664
4665 m_log.precision(12);
4666
4667 // Sum-Up over all domains
4668 MPI_Allreduce(MPI_IN_PLACE, MM.data(), count, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "MM");
4669 MPI_Allreduce(MPI_IN_PLACE, ML.data(), count, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "ML");
4670
4671 // // Normalize
4672 // for(MInt i=0; i < tmpCt[direction]; i++){
4673 // MM[i] *= ((MFloat)tmpCt[direction] / (MFloat)(tmpCt[0]*tmpCt[1]*tmpCt[2])) ;
4674 // ML[i] *= ((MFloat)tmpCt[direction] / (MFloat)(tmpCt[0]*tmpCt[1]*tmpCt[2])) ;
4675 // }
4676
4677 // Divide
4678 for(MInt i = 2; i < tmpCt[direction] - 2; i++) {
4679 if(MM[i] > 1e-12) meanTensors[i] = ML[i] / MM[i];
4680 }
4681}
4682
4688template <MInt nDim, MInt nDist, class SysEqn>
4690 TRACE();
4691 // Update the global Reynolds number if we use the tanh-adaption
4692 if(m_tanhInit && (globalTimeStep > m_initStartTime)) {
4693 const MFloat scale =
4694 0.5 * (m_tanhScaleFactor * tanh((5.0 * (MFloat)(globalTimeStep - m_initStartTime) / (MFloat)m_initTime) - 2.5))
4695 + 0.5;
4696
4697 m_Re = m_initRe + scale * (m_finalRe - m_initRe);
4698 // final timestep reached
4699 if(globalTimeStep == m_initStartTime + m_initTime) {
4700 m_Re = m_finalRe;
4701 m_tanhInit = false;
4702 }
4703 }
4704 // Required for ported functions, since GPUs cannot access the global variable globalTimeStep
4705 const MInt gTS = globalTimeStep;
4706 const MInt maxLevel_ = maxLevel();
4707 // update/reset m_nu and a_nu/a_oldNu
4708 m_nu = m_Ma * LBCS / m_Re * m_referenceLength;
4709 if(m_cells.saveOldNu()) {
4710 maia::parallelFor<true>(0, m_currentMaxNoCells, [=](MInt index) {
4711 const MInt pCellId = m_activeCellList[index];
4712 const MInt lvlDiff = maxLevel_ - a_level(pCellId);
4713 if((gTS - 1) % IPOW2(lvlDiff) != 0) return;
4714 this->a_oldNu(pCellId) = a_nu(pCellId);
4715 a_nu(pCellId) = m_nu;
4716 });
4717 } else {
4718 maia::parallelFor<true>(0, m_currentMaxNoCells, [=](MInt index) {
4719 const MInt pCellId = m_activeCellList[index];
4720 const MInt lvlDiff = maxLevel_ - a_level(pCellId);
4721 if((gTS - 1) % IPOW2(lvlDiff) != 0) return;
4722 a_nu(pCellId) = m_nu;
4723 });
4724 }
4725}
4726
4729template <MInt nDim, MInt nDist, class SysEqn>
4731 TRACE();
4732
4733 for(MInt i = 0; i < m_currentMaxNoCells; i++) {
4734 const MInt pCellId = m_activeCellList[i];
4735 swap_variables(pCellId);
4736
4737 // Update macroscopic variables
4738 a_variable(pCellId, PV->RHO) = 0.0;
4739 for(MInt j = 0; j < nDist; j++) {
4740 a_variable(pCellId, PV->RHO) += a_oldDistribution(pCellId, j);
4741 }
4742 for(MInt d = 0; d < nDim; d++) {
4743 a_variable(pCellId, PV->U + d) = 0.0;
4744 for(MInt j = 0; j < Ld::dxQyFld(); j++) {
4745 a_variable(pCellId, PV->U + d) += a_oldDistribution(pCellId, Ld::pFld(d, j));
4746 a_variable(pCellId, PV->U + d) -= a_oldDistribution(pCellId, Ld::nFld(d, j));
4747 }
4748 }
4749 }
4750}
4751
4760template <MInt nDim, MInt nDist, class SysEqn>
4762 TRACE();
4763
4764 constexpr MFloat coefficients[4] = {F1B8, F1B16, F1B32, F1B64};
4765 m_nu = m_Ma * LBCS / m_Re * m_referenceLength;
4766
4767 for(MInt id = 0; id < this->grid().noInternalCells(); id++) {
4768 //----------------------------------------
4769 // 1. calculate amount from actual cell
4770 // Calculate strain rate tensor
4771 // S_{ij} = \frac{1}{2} (\partial_j u_i + \partial_i u_j)
4772 m_omega = 2.0 / (1.0 + 6.0 * m_nu * FPOW2(maxLevel() - this->a_level(id)));
4773 MFloat Sij[9];
4774 for(MInt k = 0; k < 9; k++) {
4775 Sij[k] = -F1B2 * F1BCSsq * m_omega * m_momentumFlux[id][k];
4776 }
4777 // Calculate caracteristic filtered rate of strain
4778 MFloat S = sqrt(2.0 * std::inner_product(&Sij[0], &Sij[9], &Sij[0], .0));
4779
4780 // add values to sum
4781 MFloat Mij[9]{};
4782 MFloat SijTilde[9]{};
4783 for(MInt j = 0; j < 9; j++) {
4784 Mij[j] += coefficients[0] * 2.0 * m_deltaX * m_deltaX * S * Sij[j];
4785 SijTilde[j] += coefficients[0] * Sij[j];
4786 }
4787 MFloat uuTilde[9]{};
4788 for(MInt k = 0; k < 3; k++) {
4789 for(MInt l = 0; l < 3; l++) {
4790 uuTilde[l + 3 * k] += coefficients[0] * a_variable(id, k) * a_variable(id, l);
4791 }
4792 }
4793 MFloat uTilde[3]{};
4794 for(MInt k = 0; k < 3; k++) {
4795 uTilde[k] += coefficients[0] * a_variable(id, k);
4796 }
4797 MFloat STilde = coefficients[0] * S;
4798
4799 //----------------------------------------
4800 // 2. add amount from neighbor cells
4801 // neighbors in direction with one component
4802 for(MInt j = 0; j < Ld::distFld(0); j++) {
4803 if(!a_hasNeighbor(id, j)) continue;
4804
4805 const MInt currentNghbr = c_neighborId(id, j);
4806
4807 // Calculate strain rate tensor
4808 m_omega = 2.0 / (1.0 + 6.0 * m_nu * FPOW2(maxLevel() - this->a_level(currentNghbr)));
4809 for(MInt k = 0; k < 9; k++) {
4810 Sij[k] = -F1B2 * F1BCSsq * m_omega * m_momentumFlux[currentNghbr][k];
4811 }
4812 // Calculate caracteristic filtered rate of strain
4813 S = sqrt(2.0 * std::inner_product(&Sij[0], &Sij[9], &Sij[0], .0));
4814
4815 // add values to sum
4816 for(MInt k = 0; k < 9; k++) {
4817 Mij[k] += coefficients[1] * 2.0 * m_deltaX * m_deltaX * S * Sij[k];
4818 SijTilde[k] += coefficients[1] * Sij[k];
4819 }
4820 for(MInt k = 0; k < 3; k++) {
4821 for(MInt l = 0; l < 3; l++) {
4822 uuTilde[l + 3 * k] += coefficients[1] * a_variable(id, k) * a_variable(id, l);
4823 }
4824 }
4825 for(MInt k = 0; k < 3; k++) {
4826 uTilde[k] += coefficients[1] * a_variable(id, k);
4827 }
4828 STilde += coefficients[1] * S;
4829 }
4830 // neighbors in direction with two components
4831 MInt tmpDir = Ld::distFld(0);
4832 for(MInt j = 0; j < Ld::distFld(1); j++) {
4833 if(!a_hasNeighbor(id, tmpDir + j)) continue;
4834
4835 const MInt currentNghbr = c_neighborId(id, tmpDir + j);
4836
4837 // Calculate strain rate tensor
4838 m_omega = 2.0 / (1.0 + 6.0 * m_nu * FPOW2(maxLevel() - this->a_level(currentNghbr)));
4839 for(MInt k = 0; k < 9; k++) {
4840 Sij[k] = -F1B2 * F1BCSsq * m_omega * m_momentumFlux[currentNghbr][k];
4841 }
4842 // Calculate caracteristic filtered rate of strain
4843 S = sqrt(2.0 * std::inner_product(&Sij[0], &Sij[9], &Sij[0], .0));
4844
4845 // add values to sum
4846 for(MInt i = 0; i < 9; i++) {
4847 Mij[i] += coefficients[2] * 2.0 * m_deltaX * m_deltaX * S * Sij[i];
4848 SijTilde[i] += coefficients[2] * Sij[i];
4849 }
4850 for(MInt k = 0; k < 3; k++) {
4851 for(MInt l = 0; l < 3; l++) {
4852 uuTilde[l + 3 * k] += coefficients[2] * a_variable(id, k) * a_variable(id, l);
4853 }
4854 }
4855 for(MInt k = 0; k < 3; k++) {
4856 uTilde[k] += coefficients[2] * a_variable(id, k);
4857 }
4858 STilde += coefficients[2] * S;
4859 }
4860 // neighbors in direction with three components
4861 tmpDir = Ld::distFld(0) + Ld::distFld(1);
4862 for(MInt j = 0; j < Ld::distFld(2); j++) {
4863 if(!a_hasNeighbor(id, tmpDir + j)) continue;
4864
4865 const MInt currentNghbr = c_neighborId(id, tmpDir + j);
4866
4867 // Calculate strain rate tensor
4868 m_omega = 2.0 / (1.0 + 6.0 * m_nu * FPOW2(maxLevel() - this->a_level(currentNghbr)));
4869 for(MInt k = 0; k < 9; k++) {
4870 Sij[k] = -F1B2 * F1BCSsq * m_omega * m_momentumFlux[currentNghbr][k];
4871 }
4872 // Calculate caracteristic filtered rate of strain
4873 S = sqrt(2.0 * std::inner_product(&Sij[0], &Sij[9], &Sij[0], .0));
4874
4875 // add values to sum
4876 for(MInt k = 0; k < 9; k++) {
4877 Mij[k] += coefficients[3] * 2.0 * m_deltaX * m_deltaX * S * Sij[k];
4878 SijTilde[k] += coefficients[3] * Sij[k];
4879 }
4880 for(MInt k = 0; k < 3; k++) {
4881 for(MInt l = 0; l < 3; l++) {
4882 uuTilde[l + 3 * k] += coefficients[3] * a_variable(id, k) * a_variable(id, l);
4883 }
4884 }
4885 for(MInt k = 0; k < 3; k++) {
4886 uTilde[k] += coefficients[3] * a_variable(id, k);
4887 }
4888 STilde += coefficients[3] * S;
4889 }
4890 //----------------------------------------
4891
4892
4893 // finalize Mij and Lij
4894 for(MInt j = 0; j < 9; j++) {
4895 Mij[j] -= 2.0 * 4.0 * m_deltaX * m_deltaX * STilde * SijTilde[j];
4896 }
4897
4898 MFloat Lij[9]{};
4899 for(MInt k = 0; k < 3; k++) {
4900 for(MInt l = 0; l < 3; l++) {
4901 Lij[l + 3 * k] += uuTilde[l + 3 * k] - uTilde[k] * uTilde[l];
4902 }
4903 }
4904
4905 // Multiply Mij by itself
4906 m_MijMij[id] = 0.0;
4907 for(MInt k = 0; k < 9; k++) {
4908 m_MijMij[id] += Mij[k] * Mij[k];
4909 }
4910
4911 // Multiply Mij by Lij
4912 m_MijLij[id] = 0.0;
4913 for(MInt k = 0; k < 9; k++) {
4914 m_MijLij[id] += Mij[k] * Lij[k];
4915 }
4916 }
4917}
4918
4923template <MInt nDim, MInt nDist, class SysEqn>
4925 TRACE();
4926 m_srcTermController.init();
4927}
4928
4933template <MInt nDim, MInt nDist, class SysEqn>
4935 TRACE();
4936 m_srcTermController.initSrcTerms();
4937}
4938
4943template <MInt nDim, MInt nDist, class SysEqn>
4945 TRACE();
4946 m_srcTermController.apply_preCollision();
4947}
4948
4953template <MInt nDim, MInt nDist, class SysEqn>
4955 TRACE();
4956 m_srcTermController.apply_postCollision();
4957}
4958
4963template <MInt nDim, MInt nDist, class SysEqn>
4965 TRACE();
4966 m_srcTermController.apply_postPropagation();
4967}
4968
4972template <MInt nDim, MInt nDist, class SysEqn>
4974 TRACE();
4975
4976 m_bndCnd->updateVariables();
4977}
4978
4982template <MInt nDim, MInt nDist, class SysEqn>
4984 TRACE();
4985
4986 m_bndCnd->updateRHS();
4987}
4988
4992template <MInt nDim, MInt nDist, class SysEqn>
4994 TRACE();
4995 initEqDistFunctions();
4996
4997 if(m_isThermal) {
4998 initThermalEqDistFunctions();
4999 }
5000 if(m_isTransport) {
5001 initTransportEqDistFunctions();
5002 }
5003}
5004
5013template <MInt nDim, MInt nDist, class SysEqn>
5015 TRACE();
5016
5017 m_log << " + Initializing flow field..." << endl;
5018 m_log << " - init method: " << m_initMethod << endl;
5019
5020 m_smallestCellLength = (this->c_cellLengthAtLevel(maxLevel())); // macroscopic cell-Length on highest level
5021 m_nu = m_Ma * LBCS / m_Re * m_referenceLength; // viscosity on highest level
5022 m_omega = 2.0 / (1.0 + 6.0 * m_nu);
5023
5024 if(m_FftInit) {
5025 m_log << " - flow init: turbulent" << endl;
5026
5027 switch(string2enum(m_initMethod)) {
5029 m_initMethodPtr = &LbSolverDxQy::initLatticeBgkFftPipe;
5030 break;
5032 m_initMethodPtr = &LbSolverDxQy::initLatticeBgkFftChannel;
5033 break;
5035 m_initMethodPtr = &LbSolverDxQy::initLatticeBgkFftMixing;
5036 break;
5039 break;
5042 break;
5043 default: {
5044 m_log << "lbsolverdxqy::() unknown Init-Method type in combination with FftInit" << endl;
5045 cerr << "lbsolverdxqy::() unknown Init-Method type in combination with FftInit" << endl;
5046 DEBUG("lbsolverdxqy::() unknown Init-Method type in combination with FftInit" << endl, MAIA_DEBUG_ASSERTION);
5047 TERMM(1, "unknown Init-Method type in combination with FftInit");
5048 }
5049 }
5050 } else {
5051 m_log << " - flow init: laminar" << endl;
5052
5053 switch(string2enum(m_initMethod)) {
5056 break;
5059 break;
5062 break;
5065 break;
5068 break;
5071 break;
5072 case LB_FROM_ZERO_INIT:
5073 case LB_LAMINAR_INIT_PX:
5074 case LB_LAMINAR_INIT_MX:
5075 case LB_LAMINAR_INIT_PY:
5076 case LB_LAMINAR_INIT_MY:
5077 case LB_LAMINAR_INIT_PZ:
5078 case LB_LAMINAR_INIT_MZ:
5079 m_initMethodPtr = &LbSolverDxQy::initLatticeBgkLaminar;
5080 break;
5082 m_initMethodPtr = &LbSolverDxQy::initLatticeBgkLaminarPipe;
5083 break;
5084 case LB_TGV_INIT:
5085 m_initMethodPtr = &LbSolverDxQy::initLatticeBgkTGV;
5086 break;
5088 m_initMethodPtr = &LbSolverDxQy::initLatticeBgkGaussPulse;
5089 break;
5092 break;
5095 break;
5098 break;
5101 break;
5103 m_initMethodPtr = &LbSolverDxQy::initLatticeBgkVortex;
5104 break;
5106 m_initMethodPtr = &LbSolverDxQy::initLatticeBgkVortex;
5107 break;
5108 default: {
5109 m_log << "lbsolverdxqy::() unknown Init-Method type" << endl;
5110 cerr << "lbsolverdxqy::() unknown Init-Method type" << endl;
5111 DEBUG("lbsolverdxqy::() unknown Init-Method type" << endl, MAIA_DEBUG_ASSERTION);
5112 TERMM(1, "unknown Init-Method type");
5113 }
5114 }
5115 }
5116
5117 if(m_densityFluctuations)
5118 m_log << " - init density: fluctuations enanbled" << endl;
5119 else
5120 m_log << " - init density: absolute" << endl;
5121
5122 (this->*m_initMethodPtr)();
5123}
5124
5136template <MInt nDim, MInt nDist, class SysEqn>
5138 TRACE();
5139
5140 // all cells have the same density
5141 const MFloat rho = (m_densityFluctuations) ? 0.0 : 1.0;
5142
5143 for(MInt i = 0; i < a_noCells(); i++) {
5144 a_variable(i, PV->RHO) = rho;
5145 a_oldVariable(i, PV->RHO) = rho;
5146
5147 // the viscosity is saved for each cell
5148 // this is needed for subgrid modelling
5149 initNu(i, m_nu);
5150 if(m_isThermal) {
5151 a_kappa(i) = m_kappa;
5152 a_variable(i, PV->T) = 1.0;
5153 a_oldVariable(i, PV->T) = 1.0;
5154 }
5155 if(m_isTransport) {
5156 a_diffusivity(i) = m_diffusivity;
5157 a_variable(i, PV->C) = 1.0;
5158 a_oldVariable(i, PV->C) = 1.0;
5159 }
5160
5161 for(MInt dir = 1; dir < nDim; dir++) {
5162 a_variable(i, PV->VV[dir]) = 0.0;
5163 }
5164
5165 std::array<MFloat, 2 * nDim> bBox{};
5166 this->m_geometry->getBoundingBox(bBox.data());
5167 if(this->m_nonNewtonian) {
5168 const MFloat tmpWidth = fabs(bBox[nDim + 1] - bBox[1]) * F1B2;
5169 const MFloat exp = F1 + F1 / this->m_n;
5170
5171 const MFloat relPos = fabs(a_coordinate(i, 1) / tmpWidth - F1);
5172 const MFloat parabola = F1 - pow(relPos, exp);
5173
5174 a_variable(i, PV->VV[0]) = m_Ma * LBCS * parabola;
5175 } else {
5176 const MFloat halfWidth = std::max(fabs(bBox[1 + nDim]), fabs(bBox[1]));
5177 a_variable(i, PV->VV[0]) =
5178 m_Ma * LBCS
5179 * ((1 - this->m_CouettePoiseuilleRatio) * a_coordinate(i, 1) / halfWidth + this->m_CouettePoiseuilleRatio
5180 - this->m_CouettePoiseuilleRatio * (a_coordinate(i, 1) / halfWidth) * (a_coordinate(i, 1) / halfWidth));
5181 a_oldVariable(i, PV->VV[0]) = a_variable(i, PV->VV[0]);
5182 }
5183
5184 for(MInt d = 0; d < nDim; d++) {
5185 a_oldVariable(i, PV->VV[d]) = a_variable(i, PV->VV[d]);
5186 }
5187 }
5188
5189 initEqDistFunctions();
5190
5191 if(m_isThermal) {
5192 initThermalEqDistFunctions();
5193 }
5194 if(m_isTransport) {
5195 initTransportEqDistFunctions();
5196 }
5197
5198 if(this->m_nonNewtonian) {
5199 initNonEqDistFunctions();
5200 this->exchange();
5201 this->exchangeOldDistributions();
5202 }
5203}
5204
5216template <MInt nDim, MInt nDist, class SysEqn>
5218 TRACE();
5219
5220 MFloat yPlus;
5221
5222 ScratchSpace<MFloat> bBox(nDim * 2, AT_, "bBox");
5223 MIntScratchSpace o_dirs(nDim - 1, AT_, "o_dirs");
5224 MFloat* bBoxPtr = &bBox[0];
5225 m_geometry->getBoundingBox(bBoxPtr);
5226
5227 MFloat rho;
5228
5229 MInt mainDir = 0;
5230 MInt otherDirs = 0;
5231 MFloat maxLength = F0;
5232 for(MInt d = 0; d < nDim; d++) {
5233 if(fabs(bBox[d + nDim] - bBox[d]) > maxLength) {
5234 mainDir = d;
5235 maxLength = fabs(bBox[d + nDim] - bBox[d]);
5236 } else {
5237 o_dirs[otherDirs] = d;
5238 otherDirs++;
5239 }
5240 }
5241
5242 // all cells have the same density
5243 if(m_densityFluctuations)
5244 rho = 0.0;
5245 else
5246 rho = 1.0;
5247
5248 for(MInt i = 0; i < a_noCells(); i++) {
5249 MFloat radius = 0.0;
5250 for(MInt dir = 0; dir < nDim; dir++) {
5251 if(dir == mainDir) continue;
5252 radius += a_coordinate(i, dir) * a_coordinate(i, dir);
5253 }
5254 radius = sqrt(radius);
5255
5256 const MFloat tmpWidth = 0.5 * fabs(bBox[o_dirs[0] + nDim] - bBox[o_dirs[0]]);
5257
5258 yPlus = radius / tmpWidth;
5259
5260 for(MInt dir = 0; dir < nDim; dir++) {
5261 a_variable(i, PV->VV[dir]) = 0.0;
5262 }
5263 a_variable(i, PV->VV[mainDir]) = 2.0 * (1.0 - yPlus * yPlus) * m_Ma * LBCS; // v_max = 2*v_mean
5264 if(m_isThermal) {
5265 a_variable(i, PV->T) =
5266 this->m_initTemperatureKelvin - (this->m_initTemperatureKelvin - F1) * (1.0 - yPlus * yPlus);
5267 }
5268 if(m_isTransport) {
5269 a_variable(i, PV->C) = this->m_initCon - (this->m_initCon - F1) * (1.0 - yPlus * yPlus);
5270 }
5271
5272 a_variable(i, PV->RHO) = rho;
5273
5274 // the viscosity is saved for each cell
5275 // this is needed for subgrid modelling
5276 if(m_isThermal) {
5277 a_kappa(i) = m_kappa;
5278 a_variable(i, PV->T) = 1.0;
5279 a_oldVariable(i, PV->T) = 1.0;
5280 }
5281 initNu(i, m_nu);
5282 }
5283
5284 initEqDistFunctions();
5285
5286 if(m_isThermal) {
5287 initThermalEqDistFunctions();
5288 }
5289 if(m_isTransport) {
5290 initTransportEqDistFunctions();
5291 }
5292}
5293
5305template <MInt nDim, MInt nDist, class SysEqn>
5307 TRACE();
5308 IF_CONSTEXPR(nDim != 3) TERMM(1, "Only implemented for 3D");
5309
5310 MFloat rho, rho0, u[3];
5311 MFloat p, p0;
5312
5313 // all cells have the same density
5314 rho0 = F1;
5315 p0 = rho0 * F1B3;
5316
5317 for(MInt i = 0; i < a_noCells(); i++) {
5318 const MFloat xCoord = a_coordinate(i, 0);
5319 const MFloat yCoord = a_coordinate(i, 1);
5320 const MFloat zCoord = a_coordinate(i, 2);
5321
5322 const MFloat x = (cos(F2 * zCoord) + F2) * (cos(F2 * xCoord) + cos(F2 * yCoord));
5323 const MFloat y = sin(xCoord) * cos(yCoord) * cos(zCoord);
5324 const MFloat z = cos(xCoord) * sin(yCoord) * cos(zCoord);
5325
5326 p = p0 + rho0 * (m_Ma * m_Ma) * F1B3 / 16.0 * x;
5327 rho = F3 * p;
5328 u[0] = m_Ma * LBCS * y;
5329 u[1] = -m_Ma * LBCS * z;
5330 u[2] = F0;
5331
5332 a_variable(i, PV->RHO) = rho;
5333
5334 // the viscosity is saved for each cell
5335 // this is necessary for subgrid modelling
5336 initNu(i, m_nu);
5337
5338 a_variable(i, PV->U) = u[0];
5339 a_variable(i, PV->V) = u[1];
5340 a_variable(i, PV->W) = u[2];
5341 }
5342 initEqDistFunctions();
5343}
5344
5356template <MInt nDim, MInt nDist, class SysEqn>
5358 TRACE();
5359
5360 MFloat yPlus;
5361 MFloat amp = 0.1;
5362 MFloat uTau = (MFloat)m_ReTau * m_nu / m_referenceLength;
5363 ScratchSpace<MFloat> bBox(nDim * 2, AT_, "bBox");
5364 MFloat* bBoxPtr = &bBox[0];
5365 m_geometry->getBoundingBox(bBoxPtr);
5366
5367 MFloat rho;
5368
5369 // all cells have the same density
5370 if(m_densityFluctuations)
5371 rho = 0.0;
5372 else
5373 rho = 1.0;
5374
5375 const MFloat tmpWidth = fabs(bBox[1 + nDim] - bBox[1]);
5376
5377 for(MInt i = 0; i < a_noCells(); i++) {
5378 a_variable(i, PV->RHO) = rho;
5379
5380 yPlus = m_ReTau * (fabs(a_coordinate(i, 1)) / tmpWidth + 0.5);
5381
5382 if(yPlus <= 5.0) {
5383 a_variable(i, PV->U) = uTau * yPlus;
5384 } else {
5385 if(yPlus <= 30 && yPlus > 5.0) {
5386 a_variable(i, PV->U) = uTau * (C1 * log(yPlus) + C2);
5387 } else {
5388 if(yPlus > 30) {
5389 a_variable(i, PV->U) = uTau * (C3 * log(yPlus) + C4);
5390 }
5391 }
5392 }
5393
5394 // deltaU =amp * 2.0 * (0.5 - 0.2*(MFloat) (1.0*rand()/(RAND_MAX+1.0))) * u[0];
5395 a_variable(i, PV->U) += amp * 2.0 * (0.5 - (MFloat)(1.0 * rand() / (RAND_MAX + 1.0))) * a_variable(i, PV->U);
5396
5397 for(MInt dir = 1; dir < nDim; dir++) {
5398 a_variable(i, PV->VV[dir]) = amp * 2.0 * (0.5 - (MFloat)(1.0 * rand() / (RAND_MAX + 1.0))) * a_variable(i, PV->U);
5399 }
5400
5401 // the viscosity is saved for each cell
5402 // this is needed for subgrid modelling
5403 initNu(i, m_nu);
5404 }
5405 initEqDistFunctions();
5406}
5407
5419template <MInt nDim, MInt nDist, class SysEqn>
5421 TRACE();
5422
5423 MFloat yPlus;
5424 MFloat amp = 0.1;
5425 MFloat uTau = (MFloat)m_ReTau * m_nu / m_referenceLength;
5426
5427 MFloat rho;
5428
5429 // all cells have the same density
5430 if(m_densityFluctuations)
5431 rho = 0.0;
5432 else
5433 rho = 1.0;
5434
5435 // tmpWidth = 0.5 * fabs(bBox[1 + nDim]-bBox[1]);
5436 // tmpwidth equals diameter * cellLength (on maxLevel)
5437 const MFloat tmpWidth = m_referenceLength * this->c_cellLengthAtLevel(maxLevel());
5438
5439 for(MInt i = 0; i < a_noCells(); i++) {
5440 a_variable(i, PV->RHO) = rho;
5441
5442 yPlus = m_ReTau * (1.0 - fabs(a_coordinate(i, 1)) / tmpWidth);
5443
5444 if(yPlus <= 5.0) {
5445 a_variable(i, PV->U) = uTau * yPlus;
5446 } else {
5447 if(yPlus <= 30 && yPlus > 5.0) {
5448 a_variable(i, PV->U) = uTau * (C1 * log(yPlus) + C2);
5449 } else {
5450 if(yPlus > 30) {
5451 a_variable(i, PV->U) = uTau * (C3 * log(yPlus) + C4);
5452 }
5453 }
5454 }
5455
5456 // deltaU =amp * 2.0 * (0.5 - 0.2*(MFloat) (1.0*rand()/(RAND_MAX+1.0))) * u[0];
5457 a_variable(i, PV->U) += amp * 2.0 * (0.5 - (MFloat)(1.0 * rand() / (RAND_MAX + 1.0))) * a_variable(i, PV->U);
5458
5459 for(MInt dir = 1; dir < nDim; dir++) {
5460 a_variable(i, PV->VV[dir]) = amp * 2.0 * (0.5 - (MFloat)(1.0 * rand() / (RAND_MAX + 1.0))) * a_variable(i, PV->U);
5461 }
5462
5463 // the viscosity is saved for each cell
5464 // this is needed for subgrid modelling
5465 initNu(i, m_nu);
5466 }
5467 initEqDistFunctions();
5468}
5469
5481template <MInt nDim, MInt nDist, class SysEqn>
5483 TRACE();
5484 IF_CONSTEXPR(nDim != 3) TERMM(1, "Only implemented for 3D. For 2D use a channel!");
5485
5486 MFloat deltaU, deltaW; // deltaV;
5487 MFloat yPlus;
5488 MFloat amp = 0.1;
5489 MFloat uTau = (MFloat)m_ReTau * m_nu / m_referenceLength;
5490 MFloat radius = 0;
5491
5492 ScratchSpace<MFloat> bBox(nDim * 2, AT_, "bBox");
5493 MFloat* bBoxPtr = &bBox[0];
5494 m_geometry->getBoundingBox(bBoxPtr);
5495
5496 MFloat rho;
5497
5498 // all cells have the same density
5499 if(m_densityFluctuations)
5500 rho = 0.0;
5501 else
5502 rho = 1.0;
5503
5504 const MFloat tmpWidth = fabs(bBox[1 + nDim] - bBox[1]);
5505
5506 for(MInt i = 0; i < a_noCells(); i++) {
5507 radius = sqrt(a_coordinate(i, 1) * a_coordinate(i, 1) + a_coordinate(i, 2) * a_coordinate(i, 2));
5508
5509 yPlus = (1.0 - radius / tmpWidth * 2.0) * m_ReTau;
5510 if(yPlus <= 5.0) {
5511 a_variable(i, PV->U) = uTau * yPlus;
5512 } else {
5513 if(yPlus <= 30 && yPlus > 5.0) {
5514 a_variable(i, PV->U) = uTau * (C1 * log(yPlus) + C2);
5515 } else {
5516 if(yPlus > 30) {
5517 a_variable(i, PV->U) = uTau * (C3 * log(yPlus) + C4);
5518 }
5519 }
5520 }
5521
5522 deltaU = amp * 2.0 * (0.5 - (MFloat)(1.0 * rand() / (RAND_MAX + 1.0))) * a_variable(i, PV->U);
5523 a_variable(i, PV->U) += deltaU;
5524
5525 // deltaV =amp * 2.0 * (0.5 - (MFloat) (1.0*rand()/(RAND_MAX+1.0))) * a_variable(i, PV->U);
5526
5527 deltaW = amp * 2.0 * (0.5 - (MFloat)(1.0 * rand() / (RAND_MAX + 1.0))) * a_variable(i, PV->U);
5528 a_variable(i, PV->V) = 0.0;
5529 a_variable(i, PV->W) = deltaW;
5530 a_variable(i, PV->RHO) = rho;
5531
5532 // the viscosity is saved for each cell
5533 // this is needed for subgrid modelling
5534 initNu(i, m_nu);
5535 }
5536 initEqDistFunctions();
5537}
5538
5550template <MInt nDim, MInt nDist, class SysEqn>
5552 TRACE();
5553 IF_CONSTEXPR(nDim != 3) mTerm(1, AT_, "Only implemented for 3D. For 2D use a channel!");
5554
5555 MFloat amp = 0.2 * m_Ma * LBCS;
5556 MFloat GaussFactor, sigma, deltaOmega0;
5557 MFloat rho;
5558
5559 ScratchSpace<MFloat> bBox(nDim * 2, AT_, "bBox");
5560 MFloat* bBoxPtr = &bBox[0];
5561 m_geometry->getBoundingBox(bBoxPtr);
5562
5563 // all cells have the same density
5564 if(m_densityFluctuations)
5565 rho = 0.0;
5566 else
5567 rho = 1.0;
5568
5569 // initial vorticity thickness
5570 deltaOmega0 = m_referenceLength * m_smallestCellLength;
5571
5572 m_log << " initial macroscopic vorticity thickness: " << deltaOmega0 << endl;
5573
5574 // width of the Gaussian distribution for perturbation scaling
5575 // depends on initial vorticity thickness
5576 sigma = deltaOmega0;
5577
5578 for(MInt i = 0; i < a_noCells(); i++) {
5579 // set the mean velocity profile
5580 a_variable(i, PV->U) = m_Ma * LBCS * tanh(2.0 * a_coordinate(i, 1) / deltaOmega0);
5581 for(MInt dir = 1; dir < nDim; dir++) {
5582 a_variable(i, PV->VV[dir]) = 0.0;
5583 }
5584 a_variable(i, PV->RHO) = rho;
5585
5586 GaussFactor = exp(-(a_coordinate(i, 1) / sigma) * (a_coordinate(i, 1) / sigma) * F1B2);
5587
5588 a_variable(i, PV->U) += amp * F2 * (distrib(randNumGen) - F1B2) * GaussFactor;
5589
5590 for(MInt dir = 1; dir < nDim; dir++) {
5591 a_variable(i, PV->VV[dir]) = amp * F2 * (distrib(randNumGen) - F1B2) * GaussFactor;
5592 }
5593
5594 // the viscosity is saved for each cell
5595 // this is needed for subgrid modelling
5596 initNu(i, m_nu);
5597 }
5598
5599
5600 initNonEqDistFunctions();
5601}
5602
5614template <MInt nDim, MInt nDist, class SysEqn>
5616 TRACE();
5617
5618 MFloat yPlus;
5619 MFloat amp = 0.1;
5620 MFloat uTau = (MFloat)m_ReTau * m_nu / m_referenceLength;
5621 MFloat radius = 0;
5622 ScratchSpace<MFloat> bBox(nDim * 2, AT_, "bBox");
5623 MFloat* bBoxPtr = &bBox[0];
5624
5625 m_geometry->getBoundingBox(bBoxPtr);
5626
5627 MFloat rho;
5628
5629 // all cells have the same density
5630 if(m_densityFluctuations)
5631 rho = 0.0;
5632 else
5633 rho = 1.0;
5634
5635 // since interpolated bounce back is used, this is the real half diameter
5636 const MFloat tmpWidth = 0.5 * fabs(bBox[1 + nDim] - bBox[1]);
5637
5638 for(MInt i = 0; i < a_noCells(); i++) {
5639 for(MInt dir = 0; dir < nDim - 1; dir++) {
5640 radius += a_coordinate(i, dir) * a_coordinate(i, dir);
5641 }
5642 radius = sqrt(radius);
5643
5644 yPlus = m_ReTau * (1.0 - radius / tmpWidth);
5645
5646 if(yPlus <= 5.0) {
5647 a_variable(i, PV->VV[nDim - 1]) = uTau * yPlus;
5648 } else {
5649 if(yPlus <= 30 && yPlus > 5.0) {
5650 a_variable(i, PV->VV[nDim - 1]) = uTau * (C1 * log(yPlus) + C2);
5651 } else {
5652 if(yPlus > 30) {
5653 a_variable(i, PV->VV[nDim - 1]) = uTau * (C3 * log(yPlus) + C4);
5654 }
5655 }
5656 }
5657
5658 for(MInt dir = 0; dir < nDim - 1; dir++) {
5659 a_variable(i, PV->VV[dir]) =
5660 amp * 2.0 * (0.5 - (MFloat)(1.0 * rand() / (RAND_MAX + 1.0))) * a_variable(i, PV->VV[nDim - 1]);
5661 }
5662 a_variable(i, PV->VV[nDim - 1]) +=
5663 amp * 2.0 * (0.5 - (MFloat)(1.0 * rand() / (RAND_MAX + 1.0))) * a_variable(i, PV->VV[nDim - 1]);
5664 a_variable(i, PV->RHO) = rho;
5665
5666 // the viscosity is saved for each cell
5667 // this is needed for subgrid modelling
5668 initNu(i, m_nu);
5669 }
5670 initEqDistFunctions();
5671}
5672
5689template <MInt nDim, MInt nDist, class SysEqn>
5691 TRACE();
5692
5693 MFloat coreRadius = 0.2;
5694 std::array<MFloat, 2> position;
5695 MBool eqInit = false;
5696 position.fill(0.0);
5697
5698 coreRadius = Context::getSolverProperty<MFloat>("vortexCoreRadius", this->m_solverId, AT_, &coreRadius);
5699 const MFloat umax = Context::getSolverProperty<MFloat>("vortexMachMax", this->m_solverId, AT_, &m_Ma) * LBCS;
5700 eqInit = Context::getSolverProperty<MBool>("vortexEqInit", this->m_solverId, AT_, &eqInit);
5701 if(Context::propertyExists("vortexPosition", this->m_solverId)) {
5702 for(MInt d = 0; d < 2; d++) {
5703 position[d] = Context::getSolverProperty<MFloat>("vortexPosition", this->m_solverId, AT_, d);
5704 }
5705 }
5706
5707 std::array<MFloat, 2> u_b = {0.0, 0.0};
5708 if(string2enum(m_initMethod) == LB_CONVECTING_VORTEX_INIT) {
5709 u_b[0] = m_Ma * LBCS;
5710 }
5711
5712 if(domainId() == 0) {
5713 std::stringstream ss;
5714 ss << "Info: " << string2enum(m_initMethod) << std::endl;
5715 ss << " vortexCoreRadius : " << coreRadius << std::endl;
5716 ss << " vortexUmax : " << umax << std::endl;
5717 ss << " vortexPosition : " << position[0] << ", " << position[1] << std::endl;
5718 std::cout << ss.str();
5719 }
5720
5721 maia::parallelFor<false>(0, a_noCells(), [=](MInt cellId) {
5722 const MFloat x = a_coordinate(cellId, 0) - position[0];
5723 const MFloat y = a_coordinate(cellId, 1) - position[1];
5724 const MFloat r_rel = std::sqrt(POW2(x) + POW2(y)) / coreRadius;
5725 const MFloat theta = std::atan2(y, x);
5726 const MFloat factor = umax * std::exp(0.5);
5727 // Determine velocity from potential flow theory (x and y direction)
5728 MFloat up[2] = {0.0, 0.0};
5729 {
5730 const MFloat u_tan = factor * r_rel * std::exp(-0.5 * POW2(r_rel));
5731 up[0] = -std::sin(theta) * u_tan;
5732 up[1] = std::cos(theta) * u_tan;
5733 }
5734 const MFloat rho0 = 1.0;
5735 // const MFloat rho = rho0 * std::exp(-POW2(factor) / (2.0 * CSsq) * std::exp(1.0 - POW2(r_rel)));
5736 const MFloat rho = rho0 * std::exp(-0.5 * POW2(factor * F1BCS) * std::exp(-POW2(r_rel)));
5737 a_variable(cellId, PV->RHO) = rho;
5738 a_variable(cellId, PV->U) = (u_b[0] + up[0]);
5739 a_variable(cellId, PV->V) = (u_b[1] + up[1]);
5740 if constexpr(nDim == 3) a_variable(cellId, PV->W) = 0.0;
5741 initNu(cellId, m_nu);
5742 });
5743 if(eqInit) {
5744 initEqDistFunctions();
5745 } else {
5746 initNonEqDistFunctions();
5747 }
5748}
5749
5761template <MInt nDim, MInt nDist, class SysEqn>
5763 TRACE();
5764
5765 // normal zero init
5766 // initLatticeBgkLaminarDir(-1);
5767
5768 // Fixed values for initial time and density
5769 const MFloat t = 0.0;
5770 // const MFloat gamma = Context::getSolverProperty<MFloat>("circulation", this->m_solverId, AT_);
5771 const MFloat r0 = Context::getSolverProperty<MFloat>("r0", this->m_solverId, AT_);
5772 const MFloat rC = Context::getSolverProperty<MFloat>("coreRadius", this->m_solverId, AT_);
5773 // Vatistas vortex core model (nC = 1 corresponds to Scully model)
5774 MInt nC = 1;
5775 nC = Context::getSolverProperty<MInt>("coreModelExponent", this->m_solverId, AT_, &nC);
5776 // Calculate rotation frequency and offsets
5777 const MFloat gamma = m_Ma * LBCS * 4.0 * PI * r0; // units !: [u_lb * l_stl]
5778 const MFloat dx = (this->c_cellLengthAtLevel(maxLevel()));
5779 const MFloat omega = m_Ma * LBCS / (r0 / dx);
5780 const MFloat bx = r0 * cos(omega * t);
5781 const MFloat by = r0 * sin(omega * t);
5782
5783 const MFloat periode = 2.0 * PI / omega;
5784 m_log << " Info spinning vorticities init: " << std::endl
5785 << " * Iterations for one full rotation: " << periode << std::endl;
5786 const MFloat resolutionFactor = rC / dx;
5787 m_log << " * coreRadius / dx_maxLevel = " << resolutionFactor << std::endl;
5788
5789
5790 // Set initial condition for all cells
5791 maia::parallelFor<false>(0, a_noCells(), [=](MInt cellId) {
5792 // Calculate vortex-local coordinates
5793 const MFloat x = a_coordinate(cellId, 0);
5794 const MFloat y = a_coordinate(cellId, 1);
5795 const MFloat rPos = std::sqrt(POW2(x - bx) + POW2(y - by));
5796 const MFloat thetaPos = std::atan2(y - by, x - bx);
5797 const MFloat rNeg = std::sqrt(POW2(x + bx) + POW2(y + by));
5798 const MFloat thetaNeg = std::atan2(y + by, x + bx);
5799
5800 // Determine velocity from potential flow theory (x and y direction)
5801 MFloat u[2] = {0.0, 0.0};
5802 {
5803 const MFloat factorPos = (nC == 1) ? rPos / (rC * rC + rPos * rPos)
5804 : rPos / std::pow(std::pow(rC, 2 * nC) + std::pow(rPos, 2 * nC), 1.0 / nC);
5805 const MFloat factorNeg = (nC == 1) ? rNeg / (rC * rC + rNeg * rNeg)
5806 : rNeg / std::pow(std::pow(rC, 2 * nC) + std::pow(rNeg, 2 * nC), 1.0 / nC);
5807 u[0] = (factorPos * std::sin(thetaPos) + factorNeg * std::sin(thetaNeg)) * (-gamma / 2.0 / PI);
5808 u[1] = (factorPos * std::cos(thetaPos) + factorNeg * std::cos(thetaNeg)) * (gamma / 2.0 / PI);
5809 }
5810
5811 // Set macroscopic variables
5812 // Determine pressure using steady-state Bernoulli equation
5813 const MFloat usqrB2 = 0.5 * (u[0] * u[0] + u[1] * u[1]);
5814 // const MFloat rho = 1.0 - usqrB2 / (CSsq + usqrB2);
5815 const MFloat rho = 1.0 / (1.0 + usqrB2 * F1BCSsq);
5816 a_variable(cellId, PV->RHO) = rho;
5817 a_variable(cellId, PV->U) = rho * u[0];
5818 a_variable(cellId, PV->V) = rho * u[1];
5819 a_oldVariable(cellId, PV->U) = a_variable(cellId, PV->U);
5820 a_oldVariable(cellId, PV->V) = a_variable(cellId, PV->V);
5821 if constexpr(nDim == 3) {
5822 a_variable(cellId, PV->W) = 0.0;
5823 a_oldVariable(cellId, PV->W) = 0.0;
5824 }
5825 initNu(cellId, m_nu);
5826 });
5827
5828 initEqDistFunctions();
5829}
5830
5845template <MInt nDim, MInt nDist, class SysEqn>
5847 TRACE();
5848
5849 switch(string2enum(m_initMethod)) {
5850 case LB_FROM_ZERO_INIT:
5851 if constexpr(nDim == 2) {
5852 m_log << " - parameters: u=0.0, v=0.0, " << (m_densityFluctuations ? "rho=0.0" : "rho=1.0")
5853 << ((m_isThermal) ? ", T=1.0" : "") << ((m_isTransport) ? ", C=1.0" : "") << endl;
5854 } else {
5855 m_log << " - parameters: u=0.0, v=0.0, w=0, " << (m_densityFluctuations ? "rho=0.0" : "rho=1.0")
5856 << ((m_isThermal) ? ", T=1.0" : "") << ((m_isTransport) ? ", C=1.0" : "") << endl;
5857 }
5858 initLatticeBgkLaminarDir(-1);
5859 break;
5860 case LB_LAMINAR_INIT_PX:
5861 if constexpr(nDim == 2) {
5862 m_log << " - parameters: u=" << m_Ma * LBCS << ", v=0.0, "
5863 << (m_densityFluctuations ? "rho=0.0" : "rho=1.0") << ((m_isThermal) ? ", T=1.0" : "")
5864 << ((m_isTransport) ? ", C=1.0" : "") << endl;
5865 } else {
5866 m_log << " - parameters: u=" << m_Ma * LBCS << ", v=0.0, w=0, "
5867 << (m_densityFluctuations ? "rho=0.0" : "rho=1.0") << ((m_isThermal) ? ", T=1.0" : "")
5868 << ((m_isTransport) ? ", C=1.0" : "") << endl;
5869 }
5870 initLatticeBgkLaminarDir(0);
5871 break;
5872 case LB_LAMINAR_INIT_MX:
5873 if constexpr(nDim == 2) {
5874 m_log << " - parameters: u=-" << m_Ma * LBCS << ", v=0.0, "
5875 << (m_densityFluctuations ? "rho=0.0" : "rho=1.0") << ((m_isThermal) ? ", T=1.0" : "")
5876 << ((m_isTransport) ? ", C=1.0" : "") << endl;
5877 } else {
5878 m_log << " - parameters: u=-" << m_Ma * LBCS << ", v=0.0, w=0, "
5879 << (m_densityFluctuations ? "rho=0.0" : "rho=1.0") << ((m_isThermal) ? ", T=1.0" : "")
5880 << ((m_isTransport) ? ", C=1.0" : "") << endl;
5881 }
5882 initLatticeBgkLaminarDir(1);
5883 break;
5884 case LB_LAMINAR_INIT_PY:
5885 if constexpr(nDim == 2) {
5886 m_log << " - parameters: u=0.0, v=" << m_Ma * LBCS << ", "
5887 << (m_densityFluctuations ? "rho=0.0" : "rho=1.0") << ((m_isThermal) ? ", T=1.0" : "")
5888 << ((m_isTransport) ? ", C=1.0" : "") << endl;
5889 } else {
5890 m_log << " - parameters: u=0.0, v=" << m_Ma * LBCS << ", w=0.0, "
5891 << (m_densityFluctuations ? "rho=0.0" : "rho=1.0") << ((m_isThermal) ? ", T=1.0" : "")
5892 << ((m_isTransport) ? ", C=1.0" : "") << endl;
5893 }
5894 initLatticeBgkLaminarDir(2);
5895 break;
5896 case LB_LAMINAR_INIT_MY:
5897 if constexpr(nDim == 2) {
5898 m_log << " - parameters: u=0.0, v=-" << m_Ma * LBCS << ", "
5899 << (m_densityFluctuations ? "rho=0.0" : "rho=1.0") << ((m_isThermal) ? ", T=1.0" : "")
5900 << ((m_isTransport) ? ", C=1.0" : "") << endl;
5901 } else {
5902 m_log << " - parameters: u=0.0, v=-" << m_Ma * LBCS << ", w=0.0, "
5903 << (m_densityFluctuations ? "rho=0.0" : "rho=1.0") << ((m_isThermal) ? ", T=1.0" : "")
5904 << ((m_isTransport) ? ", C=1.0" : "") << endl;
5905 }
5906 initLatticeBgkLaminarDir(3);
5907 break;
5908 case LB_LAMINAR_INIT_PZ:
5909 if constexpr(nDim == 2) {
5910 m_log << " - parameters: u=0.0, v=0.0, " << (m_densityFluctuations ? "rho=0.0" : "rho=1.0")
5911 << ((m_isThermal) ? ", T=1.0" : "") << ((m_isTransport) ? ", C=1.0" : "") << endl;
5912 initLatticeBgkLaminarDir(-1);
5913 } else {
5914 m_log << " - parameters: u=0.0, v=0.0, w=" << m_Ma * LBCS << ", "
5915 << (m_densityFluctuations ? "rho=0.0" : "rho=1.0") << ((m_isThermal) ? ", T=1.0" : "")
5916 << ((m_isTransport) ? ", C=1.0" : "") << endl;
5917 initLatticeBgkLaminarDir(4);
5918 }
5919 break;
5920 case LB_LAMINAR_INIT_MZ:
5921 if constexpr(nDim == 2) {
5922 m_log << " - parameters: u=0.0, v=0.0, " << (m_densityFluctuations ? "rho=0.0" : "rho=1.0")
5923 << ((m_isThermal) ? ", T=1.0" : "") << ((m_isTransport) ? ", C=1.0" : "") << endl;
5924 initLatticeBgkLaminarDir(-1);
5925 } else {
5926 m_log << " - parameters: u=0.0, v=0.0, w=-" << m_Ma * LBCS << ", "
5927 << (m_densityFluctuations ? "rho=0.0" : "rho=1.0") << ((m_isThermal) ? ", T=1.0" : "")
5928 << ((m_isTransport) ? ", C=1.0" : "") << endl;
5929 initLatticeBgkLaminarDir(5);
5930 }
5931 break;
5932 default:
5933 break;
5934 }
5935}
5936
5948template <MInt nDim, MInt nDist, class SysEqn>
5950 TRACE();
5951
5952 const MFloat rho0 = (m_densityFluctuations) ? 0.0 : 1.0;
5953 const MFloat origin[3] = {F0, F0, F0};
5954 const MFloat amp = 1e-8;
5955 const MFloat radius = 0.01;
5956
5957 initLatticeBgkLaminarDir(-1); // normal zero init
5958 maia::parallelFor<false>(0, a_noCells(), [&](MInt i) {
5959 MFloat r[nDim];
5960 for(MInt j = 0; j < nDim; j++)
5961 r[j] = a_coordinate(i, j) - origin[j];
5962 const MFloat distance = std::sqrt(std::inner_product(&r[0], &r[nDim], &r[0], .0));
5963 const MFloat rhoFluct = amp * std::exp(-(distance * distance) / radius);
5964 a_variable(i, PV->RHO) = rho0 + rhoFluct;
5965 a_oldVariable(i, PV->RHO) = a_variable(i, PV->RHO);
5966 });
5967 initEqDistFunctions();
5968}
5969
5970// Initialize a Gaussian hill for diffusion processes. The velocity set uniform to zero.
5971// Set property "initMethod" to "LB_GAUSS_HILL_DIFFUSION" to use this function.
5972// Note this has to be used together with the "solverMethod" = "MAIA_LATTICE_BGK_TRANSPORT"
5973// as well as that this can only used in "2D".
5974template <MInt nDim, MInt nDist, class SysEqn>
5976 TRACE();
5977
5978 const MFloat origin[2] = {F0, F0}; // center of the hill
5979 const MFloat width = 20.0 * this->c_cellLengthAtLevel(this->maxLevel());
5980 const MFloat maxConcentration = this->m_initCon;
5981 const MFloat maxTemp = this->m_initTemperatureKelvin;
5982
5983 maia::parallelFor<false>(0, a_noCells(), [=](MInt i) {
5984 // Initialize zero velocity
5985 a_variable(i, PV->U) = F0;
5986 a_variable(i, PV->V) = F0;
5987 a_oldVariable(i, PV->U) = F0;
5988 a_oldVariable(i, PV->V) = F0;
5989
5990 // Inizialize density
5991 MFloat rho = 1.0;
5992 a_variable(i, PV->RHO) = rho;
5993 a_oldVariable(i, PV->RHO) = rho;
5994
5995 // Initialize a Gaussian hill for the conzentration.
5996 if((m_isTransport) && nDim == 2) {
5997 MFloat r[nDim];
5998 for(MInt d = 0; d < nDim; d++)
5999 r[d] = a_coordinate(i, d) - origin[d];
6000 const MFloat distSq = pow(r[0], 2) + pow(r[1], 2);
6001 const MFloat C = maxConcentration * exp(-(distSq) / (2 * pow(width, 2)));
6002 a_variable(i, PV->C) = C;
6003 a_oldVariable(i, PV->C) = C;
6004 }
6005
6006 if((m_isThermal) && nDim == 2) {
6007 MFloat r[nDim];
6008 for(MInt d = 0; d < nDim; d++)
6009 r[d] = a_coordinate(i, d) - origin[d];
6010 const MFloat distSq = pow(r[0], 2) + pow(r[1], 2);
6011 const MFloat T = maxTemp * exp(-(distSq) / (2 * pow(width, 2)));
6012 a_variable(i, PV->T) = T;
6013 a_oldVariable(i, PV->T) = T;
6014 }
6015
6016 // the viscosity is saved for each cell
6017 // this is needed for subgrid modelling
6018 initNu(i, m_nu);
6019 });
6020
6021 // Compute the equilibrium distributions
6022 initEqDistFunctions();
6023
6024 if(m_isThermal) {
6025 initThermalEqDistFunctions();
6026 }
6027 if(m_isTransport) {
6028 initTransportEqDistFunctions();
6029 }
6030}
6031
6032// Initialize a Gaussian hill for diffusion processes. The velocity set uniform to zero.
6033// Set property "initMethod" to "LB_GAUSS_HILL_ADVECTION" to use this function.
6034// Note this has to be used together with the "solverMethod" = "MAIA_LATTICE_BGK_TRANSPORT"
6035// as well as that this can only used in "2D".
6036template <MInt nDim, MInt nDist, class SysEqn>
6038 TRACE();
6039
6040 const MFloat origin[2] = {F0, F0}; // center of the hill
6041 const MFloat width = 20.0 * this->c_cellLengthAtLevel(this->maxLevel());
6042 const MFloat maxConcentration = this->m_initCon;
6043 const MFloat maxTemp = this->m_initTemperatureKelvin;
6044
6045 maia::parallelFor<false>(0, a_noCells(), [&](MInt i) {
6046 // Initialize zero velocity
6047 MFloat velocity = m_Ma * LBCS;
6048 a_variable(i, PV->U) = velocity;
6049 a_variable(i, PV->V) = velocity;
6050 a_oldVariable(i, PV->U) = velocity;
6051 a_oldVariable(i, PV->V) = velocity;
6052
6053 // Inizialize density
6054 MFloat rho = 1.0;
6055 a_variable(i, PV->RHO) = rho;
6056 a_oldVariable(i, PV->RHO) = rho;
6057
6058 // Initialize a Gaussian hill for the conzentration.
6059 if((m_isTransport) && nDim == 2) {
6060 MFloat r[nDim];
6061 for(MInt d = 0; d < nDim; d++)
6062 r[d] = a_coordinate(i, d) - origin[d];
6063 const MFloat distSq = pow(r[0], 2) + pow(r[1], 2);
6064 const MFloat C = maxConcentration * exp(-(distSq) / (2 * pow(width, 2)));
6065 a_variable(i, PV->C) = C;
6066 a_oldVariable(i, PV->C) = C;
6067 }
6068
6069 if((m_isThermal) && nDim == 2) {
6070 MFloat r[nDim];
6071 for(MInt d = 0; d < nDim; d++)
6072 r[d] = a_coordinate(i, d) - origin[d];
6073 const MFloat distSq = pow(r[0], 2) + pow(r[1], 2);
6074 const MFloat T = maxTemp * exp(-(distSq) / (2 * pow(width, 2)));
6075 a_variable(i, PV->T) = T;
6076 a_oldVariable(i, PV->T) = T;
6077 }
6078
6079 // the viscosity is saved for each cell
6080 // this is needed for subgrid modelling
6081 initNu(i, m_nu);
6082 });
6083
6084 // Compute the equilibrium distributions
6085 initEqDistFunctions();
6086
6087 if(m_isThermal) {
6088 initThermalEqDistFunctions();
6089 }
6090 if(m_isTransport) {
6091 initTransportEqDistFunctions();
6092 }
6093}
6094
6107template <MInt nDim, MInt nDist, class SysEqn>
6109 // normal init in pos +x direction
6110 initLatticeBgkLaminarDir(0);
6111 // now add perturbation to force faster transient
6112 constexpr MFloat factor = 0.1;
6113 const MFloat bb = 2.0; // bounding box where perturbation is applied
6114 maia::parallelFor<false>(0, a_noCells(), [=](MInt i) {
6115 const MFloat x = a_coordinate(i, 0);
6116 const MFloat y = a_coordinate(i, 1);
6117 // (x,y) in bb
6118 if(-bb < x && x < bb && -bb < y && y < bb) {
6119 const MFloat pertFactor = (1.0 + factor * std::sin(y / 2.0 * PI));
6120 a_variable(i, PV->U) *= pertFactor;
6121 }
6122 });
6123 initEqDistFunctions();
6124}
6125
6140template <MInt nDim, MInt nDist, class SysEqn>
6142 TRACE();
6143
6144 MFloat value = m_Ma * LBCS;
6145 std::array<MInt, nDim - 1> o_dirs{};
6146 o_dirs[0] = PV->V;
6147 if constexpr(nDim == 3) o_dirs[1] = PV->W;
6148
6149 if(dir < 0) {
6150 dir = PV->U;
6151 value = 0.0;
6152 } else {
6153 if(dir % 2) value *= -1.0;
6154
6155 switch(dir) {
6156 case 0:
6157 case 1:
6158 dir = PV->U;
6159 break;
6160 case 2:
6161 case 3:
6162 dir = PV->V;
6163 o_dirs[0] = PV->U;
6164 break;
6165 case 4:
6166 case 5:
6167 dir = PV->W;
6168 o_dirs[0] = PV->U;
6169 if constexpr(nDim == 3) o_dirs[1] = PV->V;
6170 break;
6171 default:
6172 break;
6173 }
6174 }
6175
6176 maia::parallelFor<false>(0, a_noCells(), [=](MInt i) {
6177 a_variable(i, dir) = value;
6178 a_oldVariable(i, dir) = value;
6179 for(MInt j = 0; j < nDim - 1; j++) {
6180 a_variable(i, o_dirs[j]) = 0.0;
6181 a_oldVariable(i, o_dirs[j]) = 0.0;
6182 }
6183
6184 MFloat rho = m_densityFluctuations ? 0.0 : 1.0;
6185 if(m_initDensityGradient) {
6186 for(MInt j = 0; j < nDim; j++) {
6187 rho += a_coordinate(i, j) / this->c_cellLengthAtLevel(maxLevel()) * m_volumeAccel[j] * F1BCSsq;
6188 }
6189 }
6190 a_variable(i, PV->RHO) = rho;
6191 a_oldVariable(i, PV->RHO) = rho;
6192
6193 if(m_isThermal) {
6194 a_kappa(i) = m_kappa;
6195 a_variable(i, PV->T) = 1.0;
6196 a_oldVariable(i, PV->T) = 1.0;
6197 }
6198 if(m_isTransport) {
6199 a_variable(i, PV->C) = 0.0;
6200 a_oldVariable(i, PV->C) = 0.0;
6201 }
6202
6203 // the viscosity is saved for each cell
6204 // this is needed for subgrid modelling
6205 initNu(i, m_nu);
6206 });
6207
6208 initEqDistFunctions();
6209
6210 if(m_isThermal) {
6211 initThermalEqDistFunctions();
6212 }
6213 if(m_isTransport) {
6214 initTransportEqDistFunctions();
6215 }
6216}
6217
6223template <MInt nDim, MInt nDist, class SysEqn>
6225 TRACE();
6226
6227 for(MInt i = 0; i < a_noCells(); i++) {
6228 const MFloat rho = a_variable(i, PV->RHO);
6229 std::array<MFloat, nDim> u;
6230 for(MInt d = 0; d < nDim; d++) {
6231 u[d] = a_variable(i, d);
6232 }
6233 setEqDists(i, rho, u.data());
6234 }
6235}
6236
6237template <MInt nDim, MInt nDist, class SysEqn>
6239 TRACE();
6240 // first init equilibrium everywhere
6241 initEqDistFunctions();
6242
6243 // now add non-equilibrium part
6244 maia::parallelFor<false>(0, a_noCells(), [&](MInt i) {
6245 // calculate spatial derivatives of velocity vector in the current cell center
6246 MFloat c[nDim][nDim]; // dv/dz = c[1][2]
6247 this->calculateVelocityDerivative(i, c);
6248
6249 MFloat trace = 0.0;
6250 for(MInt d = 0; d < nDim; d++) {
6251 trace += c[d][d];
6252 }
6253
6254 // add non-eq parts
6255 // cf. Eq (5.88), Krueger et al., 2017, https://doi.org/10.1007/978-3-319-44649-3 .
6256 const MInt lvlDiff = maxLevel() - a_level(i);
6257 const MFloat tau = F1B2 + F1BCSsq * a_nu(i) * FFPOW2(lvlDiff); // tau_0
6258 const MFloat tauRho = tau * a_variable(i, PV->RHO);
6259 for(MInt dist = 0; dist < nDist - 1; dist++) {
6260 const MFloat t = Ld::tp(Ld::distType(dist));
6261 a_distribution(i, dist) += t * tauRho * trace;
6262 for(MInt k = 0; k < nDim; k++) {
6263 for(MInt l = 0; l < nDim; l++) {
6264 a_distribution(i, dist) -=
6265 t * tauRho * F1BCSsq * (Ld::idFld(dist, k) - 1) * (Ld::idFld(dist, l) - 1) * c[l][k];
6266 }
6267 }
6268 }
6269 a_distribution(i, Ld::lastId()) += Ld::tp(0) * tauRho * trace;
6270
6271 // oldDist = dist
6272 for(MInt j = 0; j < Ld::lastId() + 1; j++) {
6273 a_oldDistribution(i, j) = a_distribution(i, j);
6274 }
6275 });
6276}
6277
6287template <MInt nDim, MInt nDist, class SysEqn>
6289 TRACE();
6290
6291 for(MInt i = 0; i < a_noCells(); i++) {
6292 const MFloat rho = a_variable(i, PV->RHO);
6293 const MFloat t = a_variable(i, PV->T);
6294 std::array<MFloat, nDim> u;
6295 for(MInt d = 0; d < nDim; d++) {
6296 u[d] = a_variable(i, d);
6297 }
6298
6299 setEqDistsThermal(i, t, rho, u.data());
6300 }
6301}
6302
6312template <MInt nDim, MInt nDist, class SysEqn>
6314 TRACE();
6315
6316 for(MInt i = 0; i < a_noCells(); i++) {
6317 const MFloat c = a_variable(i, PV->C);
6318 std::array<MFloat, nDim> u;
6319 for(MInt d = 0; d < nDim; d++) {
6320 u[d] = a_variable(i, d);
6321 }
6322
6323 setEqDistsTransport(i, c, u.data());
6324 }
6325}
6326
6339template <MInt nDim, MInt nDist, class SysEqn>
6341 TRACE();
6342
6343 if(domainId() == 0) mRes.open(m_resFileName, std::ofstream::app);
6344
6345 constexpr MInt noVars = 1 + nDim;
6346 for(MInt v = 0; v < noVars; v++) {
6347 m_residual[v] = F0;
6348 m_tmpResidual[v] = F0;
6349 m_tmpResidualLvl[v] = 0;
6350 m_maxResId[v] = -1;
6351 }
6352
6353 MInt count = 0;
6354 MInt sumCount = 0;
6355
6356 for(MInt id = 0; id < m_currentMaxNoCells; id++) {
6357 MInt l_id = m_activeCellList[id];
6358
6359 // skip halo cells
6360 if(l_id >= this->grid().noInternalCells()) continue;
6361
6362 const MInt pCellId = l_id;
6363
6364 // skip interfacechildren
6365 if(a_isInterfaceChild(pCellId)) continue;
6366
6367 MFloat diff[noVars] = {F0};
6368 const MFloat* const pcoordinates = &a_coordinate(pCellId, 0);
6369 MInt level = this->a_level(pCellId);
6370
6371 for(MInt v = 0; v < noVars; v++) {
6372 diff[v] = fabs(a_variable(pCellId, v) - a_oldVariable(pCellId, v));
6373 m_residual[v] += diff[v];
6374 if(m_tmpResidual[v] * m_tmpResidual[v] <= diff[v] * diff[v]) {
6375 m_tmpResidual[v] = diff[v];
6376 m_maxResId[v] = l_id;
6377 for(MInt d = 0; d < nDim; d++) {
6378 m_rescoordinates[v][d] = pcoordinates[d];
6379 }
6380 m_tmpResidualLvl[v] = level;
6381 }
6382 }
6383 count++;
6384 }
6385 cerr.precision(7);
6386
6387 stringstream res_t;
6388 res_t << globalTimeStep;
6389 MString res_t_f = res_t.str();
6390
6391 stringstream res_Re;
6392 res_Re << (m_referenceLength * m_Ma * LBCS / m_nu);
6393 MString res_Re_f = res_Re.str();
6394
6395 struct {
6396 MFloat val;
6397 MInt rank;
6398 } sendBufRes[noVars], rcvBufRes[noVars];
6399
6400 MFloat sendBufResAvg[noVars] = {0.0};
6401 for(MInt v = 0; v < noVars; v++) {
6402 sendBufResAvg[v] = m_residual[v];
6403 sendBufRes[v].val = m_tmpResidual[v];
6404 }
6405 MFloat rcvBufResAvg[noVars];
6406
6407 for(MInt i = 0; i < noVars; i++)
6408 sendBufRes[i].rank = domainId();
6409
6410 MString strs[noVars] = {};
6411 strs[0] = "U";
6412 strs[1] = "V";
6413 if constexpr(nDim == 3) strs[2] = "W";
6414 strs[nDim] = "RHO";
6415
6416 MPI_Allreduce(sendBufRes, rcvBufRes, noVars, MPI_DOUBLE_INT, MPI_MAXLOC, mpiComm(), AT_, "sendBufRes", "rcvBufRes");
6417 MPI_Reduce(sendBufResAvg, rcvBufResAvg, noVars, MPI_DOUBLE, MPI_SUM, 0, mpiComm(), AT_, "sendBufResAvg",
6418 "rcvBufResAvg");
6419
6420 // To calculate the avagare residual, get total number of cells without the halo cells
6421 if(noDomains() == 1) {
6422 // When serial, then just use the counted number of cells of the root process
6423 sumCount = count;
6424 } else {
6425 // When parallel, then sum up all counted number of cells of each process
6426 MPI_Reduce(&count, &sumCount, 1, MPI_INT, MPI_SUM, 0, mpiComm(), AT_, "count", "sumCount");
6427 }
6428
6429 // all max. averaged residuals
6430 if(domainId() == 0) {
6431 mRes << std::endl;
6432 mRes << "#------------------------------" << std::endl;
6433 mRes << "In timestep: " << res_t_f << ", with Re: " << res_Re_f << ";" << std::endl;
6434 mRes << "\n";
6435 for(MInt i = 0; i < noVars; i++)
6436 mRes << " Max. averaged residual found for " << strs[i] << " is " << (rcvBufResAvg[i] / sumCount) << "\n";
6437 }
6438
6439 if(noDomains() > 1) {
6440 for(MInt i = 0; i < noVars; i++) {
6441 MInt noElements2Snd = 0;
6442 std::array<MFloat, nDim> sndBufFloat;
6443 std::array<MInt, 2> sndBufInt;
6444 std::array<MFloat, nDim> recvElementsF;
6445 std::array<MInt, 2> recvElementsI;
6446 MIntScratchSpace noElements2SndPerCPU(noDomains(), AT_, "noElements2SndPerCPU");
6447 MIntScratchSpace posElements2SndPerCPU(noDomains(), AT_, "posElements2SndPerCPU");
6448
6449 for(MInt dom = 0; dom < noDomains(); dom++) {
6450 noElements2SndPerCPU[dom] = 0;
6451 posElements2SndPerCPU[dom] = 0;
6452 if(rcvBufRes[i].rank == dom) {
6453 noElements2SndPerCPU[dom] = nDim;
6454 }
6455 if(dom > 0) {
6456 posElements2SndPerCPU[dom] = posElements2SndPerCPU[dom - 1] + noElements2SndPerCPU[dom - 1];
6457 }
6458 }
6459
6460 if(rcvBufRes[i].rank == domainId() && m_maxResId[i] != -1) {
6461 noElements2Snd = nDim;
6462 for(MInt d = 0; d < nDim; d++) {
6463 sndBufFloat[d] = m_rescoordinates[i][d];
6464 }
6465 }
6466
6467 MPI_Gatherv(sndBufFloat.data(), noElements2Snd, MPI_DOUBLE, recvElementsF.data(), noElements2SndPerCPU.data(),
6468 posElements2SndPerCPU.data(), MPI_DOUBLE, 0, mpiComm(), AT_, "sndBufFloat.data()",
6469 "recvElementsF.data()");
6470
6471 for(MInt dom = 0; dom < noDomains(); dom++) {
6472 noElements2SndPerCPU[dom] = 0;
6473 posElements2SndPerCPU[dom] = 0;
6474 if(rcvBufRes[i].rank == dom) {
6475 noElements2SndPerCPU[dom] = 2;
6476 }
6477 if(dom > 0) {
6478 posElements2SndPerCPU[dom] = posElements2SndPerCPU[dom - 1] + noElements2SndPerCPU[dom - 1];
6479 }
6480 }
6481
6482 if(rcvBufRes[i].rank == domainId() && m_maxResId[i] != -1) {
6483 noElements2Snd = 2;
6484 sndBufInt[0] = m_tmpResidualLvl[i];
6485 sndBufInt[1] = m_maxResId[i];
6486 }
6487
6488 MPI_Gatherv(&sndBufInt, noElements2Snd, MPI_INT, recvElementsI.data(), noElements2SndPerCPU.data(),
6489 posElements2SndPerCPU.data(), MPI_INT, 0, mpiComm(), AT_, "sndBufInt", "recvElementsI.data()");
6490
6491 // all max. local residuals
6492 if(domainId() == 0) {
6493 mRes << "\n Max. local residual found for " << strs[i] << " on proc.: " << rcvBufRes[i].rank << " with "
6494 << rcvBufRes[i].val << "\n"
6495 << " Level: " << recvElementsI[0] << "\n"
6496 << " ID: " << recvElementsI[1] << "\n"
6497 << " Coordinates: (";
6498 for(MInt d = 0; d < nDim - 1; d++) {
6499 mRes << recvElementsF[d] << ", ";
6500 }
6501 mRes << recvElementsF[nDim - 1] << ")" << endl;
6502 }
6503 }
6504 } else {
6505 // Print residual for the only process that is running
6506 // No communication required
6507 for(MInt i = 0; i < noVars; i++) {
6508 mRes << "\n Max. local residual found for " << strs[i] << " on proc.: " << domainId() << " with "
6509 << rcvBufRes[i].val << "\n"
6510 << " Level: " << m_tmpResidualLvl[i] << "\n"
6511 << " ID: " << m_maxResId[i] << "\n"
6512 << " Coordinates: (";
6513 for(MInt d = 0; d < nDim - 1; d++) {
6514 mRes << m_rescoordinates[i][d] << ", ";
6515 }
6516 mRes << m_rescoordinates[i][nDim - 1] << ")" << endl;
6517 }
6518 }
6519
6520 // Close Residual file
6521 if(domainId() == 0) {
6522 mRes << std::endl;
6523 mRes.close();
6524 }
6525}
6526
6527// \brief transfer from coarse to fine
6528template <MInt nDim, MInt nDist, class SysEqn>
6530 TRACE();
6531 m_interface->prolongation();
6532}
6533
6534// \brief Transfer from fine to coarse
6535template <MInt nDim, MInt nDist, class SysEqn>
6537 TRACE();
6538 m_interface->restriction();
6539}
6540
6547template <MInt nDim, MInt nDist, class SysEqn>
6549 m_interface->removeChildren(parentId);
6550}
6551
6559template <MInt nDim, MInt nDist, class SysEqn>
6560void LbSolverDxQy<nDim, nDist, SysEqn>::refineCellLb(const MInt parentId, const MInt* childIds) {
6561 m_interface->refineCell(parentId, childIds);
6562}
6563
6576template <MInt nDim, MInt nDist, class SysEqn>
6577void LbSolverDxQy<nDim, nDist, SysEqn>::sensorInterface(std::vector<std::vector<MFloat>>& sensors,
6578 std::vector<std::bitset<64>>& sensorCellFlag,
6579 std::vector<MFloat>& sensorWeight, MInt sensorOffset,
6580 MInt sen) {
6581 m_log << " - Sensor preparation for the boundary sensor for " << m_maxNoSets << " starting from " << m_levelSetId
6582 << endl;
6583 cerr0 << " - Sensor preparation for the boundary sensor for " << m_maxNoSets << " starting from " << m_levelSetId
6584 << endl;
6585
6586 // inList > 0: Cells are marked for refinement
6587 // inList = 1: Seeding cells for markSurroundingCells
6588 MIntScratchSpace inList(a_noCells(), AT_, "inList");
6589 inList.fill(0);
6590
6591 // Fill inList with cells wich are to be refined
6592 MInt interfaceCellCounter = 0;
6593 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
6594 if(a_isHalo(cellId)) continue;
6595 if(inList[cellId] > 0) continue; // Already marked for refinement
6596
6597 if(this->a_isBndryCell(cellId)) {
6598 if(a_level(cellId) <= this->m_maxSensorRefinementLevel[sen]) {
6599 inList[cellId] = 1;
6600 interfaceCellCounter++;
6601
6602 // Propagate information to lower levels...
6603 MInt currentCellId = cellId;
6604 for(MInt parentLevel = this->a_level(cellId); parentLevel >= minLevel(); parentLevel--) {
6605 const MInt parentCellId = this->c_parentId(currentCellId);
6606 if(parentCellId == -1) {
6607 break;
6608 }
6609 inList[parentCellId] = 1;
6610 interfaceCellCounter++;
6611 currentCellId = parentCellId;
6612 }
6613 }
6614 }
6615 }
6616
6617 std::cout << "Found " << interfaceCellCounter << " static boundary cells..." << std::endl;
6618
6619 // Fill inList with cells wich are to be refined
6620 interfaceCellCounter = 0;
6621 MInt startSet = m_levelSetId;
6622 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
6623 if(a_isHalo(cellId)) continue;
6624 for(MInt set = startSet; set < m_maxNoSets; set++) {
6625 if(inList[cellId] > 0) continue; // Already marked for refinement
6626 if(fabs(a_levelSetFunctionMB(cellId, set)) < this->c_cellLengthAtCell(cellId)) {
6627 if(a_level(cellId) < this->m_maxSensorRefinementLevel[sen]) {
6628 inList[cellId] = 1;
6629 interfaceCellCounter++;
6630 }
6631 } else {
6632 for(MInt dir = 0; dir < 2 * nDim; dir++) {
6633 if(a_hasNeighbor(cellId, dir) > 0) {
6634 MInt nghbrId = c_neighborId(cellId, dir);
6635 if((a_levelSetFunctionMB(nghbrId, set) * a_levelSetFunctionMB(cellId, set) < F0)) {
6636 if(a_level(cellId) < this->m_maxSensorRefinementLevel[sen]) {
6637 inList[cellId] = 1;
6638 interfaceCellCounter++;
6639 }
6640 break;
6641 }
6642 }
6643 }
6644 }
6645 }
6646 }
6647
6648 std::cout << "Found " << interfaceCellCounter << " moving boundary cells..." << std::endl;
6649
6650 // Mark surrounding cells according to m_bandWidth
6651 for(MInt level = minLevel(); level < this->m_maxSensorRefinementLevel[sen]; level++) {
6652 this->exchangeData(inList.data());
6653 this->markSurrndCells(inList, m_bandWidth[level], level, this->m_refineDiagonals);
6654 }
6655
6656 // Transfer inList to sensor
6657 for(MInt cellId = 0; cellId < noInternalCells(); cellId++) {
6658 ASSERT(!a_isHalo(cellId), "");
6659 if(inList(cellId) == 0) {
6660 if(a_level(cellId) == minLevel()) continue;
6661 if(inList(c_parentId(cellId))) continue;
6662 if(c_isLeafCell(cellId)) {
6663 const MInt gridCellId = grid().tree().solver2grid(cellId);
6664 sensors[sensorOffset + sen][gridCellId] = -1.0;
6665 sensorCellFlag[gridCellId][sensorOffset + sen] = true;
6666 }
6667 } else {
6668 if(a_level(cellId) < this->m_maxSensorRefinementLevel[sen]) {
6669 if(c_noChildren(cellId) > 0) continue;
6670 const MInt gridCellId = grid().tree().solver2grid(cellId);
6671 sensors[sensorOffset + sen][gridCellId] = 1.0;
6672 sensorCellFlag[gridCellId][sensorOffset + sen] = true;
6673 }
6674 }
6675 }
6676 sensorWeight[sensorOffset + sen] = this->m_sensorWeight[sen];
6677}
6678
6685template <MInt nDim, MInt nDist, class SysEqn>
6686void LbSolverDxQy<nDim, nDist, SysEqn>::sensorVorticity(std::vector<std::vector<MFloat>>& sensors,
6687 std::vector<std::bitset<64>>& sensorCellFlag,
6688 std::vector<MFloat>& sensorWeight, MInt sensorOffset,
6689 MInt sen) {
6690 m_log << " - Sensor preparation for the vorticity sensor" << endl;
6691 cerr0 << " - Sensor preparation for the vorticity sensor" << endl;
6692
6693 MFloat dx = 0.0;
6694
6695 std::array<MFloat, nDim> u{};
6696 std::array<std::array<MFloat, nDim>, nDim> u_p{};
6697 std::array<std::array<MFloat, nDim>, nDim> u_m{};
6698
6699 MFloat rho = 0.0;
6700 MFloat rho_p[nDim] = {0.0};
6701 MFloat rho_m[nDim] = {0.0};
6702
6703 MFloat dudy = 0.0;
6704 MFloat dvdx = 0.0;
6705
6706 MFloat dwdx = 0.0;
6707 MFloat dwdy = 0.0;
6708
6709 MFloat phi_v = 0.0; // Sensor value vorticity
6710
6711 sensorWeight[sensorOffset + sen] = this->m_sensorWeight[sen];
6712
6713 // Set cell seize weihts
6714 // TODO labels:LB Make available by property?
6715 MFloat cellSizeWeight_v = 1.5;
6716
6717 for(MInt cellId = 0; cellId < noInternalCells(); cellId++) {
6718 ASSERT(!a_isHalo(cellId), "");
6719 const MInt gridId = this->grid().tree().solver2grid(cellId);
6720
6721 // Mesh adaptation is only performed on active cells
6722 // --> untag inactive cells
6723 if(!a_isActive(cellId)) {
6724 sensorCellFlag[gridId][sensorOffset + sen] = 0;
6725 continue;
6726 }
6727
6728 // Get cell size for cell size weighting
6729 dx = grid().cellLengthAtLevel(c_level(cellId));
6730
6731 // Compute macroscopic variables for sensor evaluation
6732 // All cells performed propagation step before. Thus, in-coming distributions
6733 // of all cells are in the same time step and comparable
6734 // --> Compute macroscopic variables from in-coming distributions.
6735 //
6736 // Depending on the neighbors of the cell, variables for
6737 // central, backwards or forwards differentials are computed
6738 calculateMacroscopicVariables(cellId, rho, u.data());
6739 if(a_hasNeighbor(cellId, 0) && a_isActive(c_neighborId(cellId, 0))) {
6740 MInt nghbrId = c_neighborId(cellId, 0);
6741 calculateMacroscopicVariables(nghbrId, rho_m[0], u_m[0].data());
6742 }
6743 if(a_hasNeighbor(cellId, 1) && a_isActive(c_neighborId(cellId, 1))) {
6744 MInt nghbrId = c_neighborId(cellId, 1);
6745 calculateMacroscopicVariables(nghbrId, rho_p[0], u_p[0].data());
6746 }
6747 if(a_hasNeighbor(cellId, 2) && a_isActive(c_neighborId(cellId, 2))) {
6748 MInt nghbrId = c_neighborId(cellId, 2);
6749 calculateMacroscopicVariables(nghbrId, rho_m[1], u_m[1].data());
6750 }
6751 if(a_hasNeighbor(cellId, 3) && a_isActive(c_neighborId(cellId, 3))) {
6752 MInt nghbrId = c_neighborId(cellId, 3);
6753 calculateMacroscopicVariables(nghbrId, rho_p[1], u_p[1].data());
6754 }
6755 if constexpr(nDim == 3) {
6756 if(a_hasNeighbor(cellId, 4) && a_isActive(c_neighborId(cellId, 4))) {
6757 MInt nghbrId = c_neighborId(cellId, 4);
6758 calculateMacroscopicVariables(nghbrId, rho_m[2], u_m[2].data());
6759 }
6760 if(a_hasNeighbor(cellId, 5) && a_isActive(c_neighborId(cellId, 5))) {
6761 MInt nghbrId = c_neighborId(cellId, 5);
6762 calculateMacroscopicVariables(nghbrId, rho_p[2], u_p[2].data());
6763 }
6764 }
6765
6766 // (1) Difference in total pressure
6767 // Incident flow total pressure depends on bc!
6768 // Here so far only for bc10000 --> Assume rho=1 on boundary.
6769 // Central differences in x-direction
6770 if((a_hasNeighbor(cellId, 0) && a_isActive(c_neighborId(cellId, 0)))
6771 && (a_hasNeighbor(cellId, 1) && a_isActive(c_neighborId(cellId, 1)))) {
6772 dvdx = (u_p[0][1] - u_m[0][1]) / (2.0 * dx);
6773 if constexpr(nDim == 3) dwdx = (u_p[0][2] - u_m[0][2]) / (2.0 * dx);
6774 }
6775 // Forwards difference in x-direction
6776 else if((!a_hasNeighbor(cellId, 0) || !a_isActive(c_neighborId(cellId, 0)))
6777 && (a_hasNeighbor(cellId, 1) && a_isActive(c_neighborId(cellId, 1)))) {
6778 dvdx = (u_p[0][1] - u[1]) / dx;
6779 if constexpr(nDim == 3) dwdx = (u_p[0][2] - u[2]) / dx;
6780 }
6781 // Backwards differences in x-direction
6782 else if((a_hasNeighbor(cellId, 0) && a_isActive(c_neighborId(cellId, 0)))
6783 && (!a_hasNeighbor(cellId, 1) || !a_isActive(c_neighborId(cellId, 1)))) {
6784 dvdx = (u[1] - u_m[0][1]) / dx;
6785 if constexpr(nDim == 3) dwdx = (u[2] - u_m[0][2]) / dx;
6786 }
6787 // Central differences in y-direction
6788 if((a_hasNeighbor(cellId, 2) && a_isActive(c_neighborId(cellId, 2)))
6789 && (a_hasNeighbor(cellId, 3) && a_isActive(c_neighborId(cellId, 3)))) {
6790 dudy = (u_p[1][0] - u_m[1][0]) / (2.0 * dx);
6791 if constexpr(nDim == 3) dwdy = (u_p[1][2] - u_m[1][2]) / (2.0 * dx);
6792 }
6793 // Forwards differences in y-direction
6794 else if((!a_hasNeighbor(cellId, 2) || !a_isActive(c_neighborId(cellId, 2)))
6795 && (a_hasNeighbor(cellId, 3) && a_isActive(c_neighborId(cellId, 3)))) {
6796 dudy = (u_p[1][0] - u[0]) / dx;
6797 if constexpr(nDim == 3) dwdy = (u_p[1][2] - u[2]) / dx;
6798 }
6799 // Backwards differences in y-direction
6800 else if((a_hasNeighbor(cellId, 2) && a_isActive(c_neighborId(cellId, 2)))
6801 && (!a_hasNeighbor(cellId, 3) || !a_isActive(c_neighborId(cellId, 3)))) {
6802 dudy = (u[0] - u_m[1][0]) / dx;
6803 if constexpr(nDim == 3) dwdy = (u[2] - u_m[1][2]) / dx;
6804 }
6805 if constexpr(nDim == 3) {
6806 MFloat dudz = 0.0;
6807 MFloat dvdz = 0.0;
6808 // Central differences in z-direction
6809 if((a_hasNeighbor(cellId, 4) && a_isActive(c_neighborId(cellId, 4)))
6810 && (a_hasNeighbor(cellId, 5) && a_isActive(c_neighborId(cellId, 5)))) {
6811 dudz = (u_p[2][0] - u_m[2][0]) / (2.0 * dx);
6812 dvdz = (u_p[2][1] - u_m[2][1]) / (2.0 * dx);
6813 }
6814 // Forwards difference in z-direction
6815 else if((!a_hasNeighbor(cellId, 4) || !a_isActive(c_neighborId(cellId, 4)))
6816 && (a_hasNeighbor(cellId, 5) && a_isActive(c_neighborId(cellId, 5)))) {
6817 dudz = (u_p[2][0] - u[0]) / dx;
6818 dvdz = (u_p[2][1] - u[1]) / dx;
6819 }
6820 // Backwards differences in z-direction
6821 else if((a_hasNeighbor(cellId, 4) && a_isActive(c_neighborId(cellId, 4)))
6822 && (!a_hasNeighbor(cellId, 5) || !a_isActive(c_neighborId(cellId, 5)))) {
6823 dudz = (u[0] - u_m[2][0]) / dx;
6824 dvdz = (u[1] - u_m[2][1]) / dx;
6825 }
6826
6827 phi_v = sqrt(pow((dwdy - dvdz), 2) + pow((dudz - dwdx), 2) + pow((dvdx - dudy), 2)) * pow(dx, cellSizeWeight_v);
6828 }
6829 if constexpr(nDim == 2) phi_v = abs(dvdx - dudy) * pow(dx, cellSizeWeight_v);
6830
6831 sensors[sensorOffset + sen][gridId] = phi_v;
6832 sensorCellFlag[gridId][sensorOffset + sen] = 1;
6833 }
6834}
6835
6842template <MInt nDim, MInt nDist, class SysEqn>
6843void LbSolverDxQy<nDim, nDist, SysEqn>::sensorDivergence(std::vector<std::vector<MFloat>>& sensors,
6844 std::vector<std::bitset<64>>& sensorCellFlag,
6845 std::vector<MFloat>& sensorWeight, MInt sensorOffset,
6846 MInt sen) {
6847 m_log << " - Sensor preparation for the divergence sensor" << endl;
6848 cerr0 << " - Sensor preparation for the divergence sensor" << endl;
6849
6850 MFloat dx = 0.0;
6851
6852 std::array<MFloat, nDim> u{};
6853 std::array<std::array<MFloat, nDim>, nDim> u_p{};
6854 std::array<std::array<MFloat, nDim>, nDim> u_m{};
6855
6856 MFloat rho = 0.0;
6857 MFloat rho_p[nDim] = {0.0};
6858 MFloat rho_m[nDim] = {0.0};
6859
6860 MFloat dudx = 0.0;
6861 MFloat dvdy = 0.0;
6862
6863 MFloat phi_m = 0.0; // Sensor value mass conservation
6864
6865 // Set sensor weights for refinement (K_f)
6866 sensorWeight[sensorOffset + sen] = this->m_sensorWeight[sen];
6867
6868 // Set cell seize weihts
6869 // TODO labels:LB Make available by property?
6870 MFloat cellSizeWeight_m = 1.0;
6871
6872 for(MInt cellId = 0; cellId < noInternalCells(); cellId++) {
6873 ASSERT(!a_isHalo(cellId), "");
6874 const MInt gridId = this->grid().tree().solver2grid(cellId);
6875
6876 // Mesh adaptation is only performed on active cells
6877 // --> untag inactive cells
6878 if(!a_isActive(cellId)) {
6879 sensorCellFlag[gridId][sensorOffset + sen] = 0;
6880 continue;
6881 }
6882
6883 // Get cell size for cell size weighting
6884 dx = grid().cellLengthAtLevel(c_level(cellId));
6885
6886 // Compute macroscopic variables for sensor evaluation
6887 // All cells performed propagation step before. Thus, in-coming distributions
6888 // of all cells are in the same time step and comparable
6889 // --> Compute macroscopic variables from in-coming distributions.
6890 //
6891 // Depending on the neighbors of the cell, variables for
6892 // central, backwards or forwards differentials are computed
6893 calculateMacroscopicVariables(cellId, rho, u.data());
6894 if(a_hasNeighbor(cellId, 0) && a_isActive(c_neighborId(cellId, 0))) {
6895 MInt nghbrId = c_neighborId(cellId, 0);
6896 calculateMacroscopicVariables(nghbrId, rho_m[0], u_m[0].data());
6897 }
6898 if(a_hasNeighbor(cellId, 1) && a_isActive(c_neighborId(cellId, 1))) {
6899 MInt nghbrId = c_neighborId(cellId, 1);
6900 calculateMacroscopicVariables(nghbrId, rho_p[0], u_p[0].data());
6901 }
6902 if(a_hasNeighbor(cellId, 2) && a_isActive(c_neighborId(cellId, 2))) {
6903 MInt nghbrId = c_neighborId(cellId, 2);
6904 calculateMacroscopicVariables(nghbrId, rho_m[1], u_m[1].data());
6905 }
6906 if(a_hasNeighbor(cellId, 3) && a_isActive(c_neighborId(cellId, 3))) {
6907 MInt nghbrId = c_neighborId(cellId, 3);
6908 calculateMacroscopicVariables(nghbrId, rho_p[1], u_p[1].data());
6909 }
6910 if constexpr(nDim == 3) {
6911 if(a_hasNeighbor(cellId, 4) && a_isActive(c_neighborId(cellId, 4))) {
6912 MInt nghbrId = c_neighborId(cellId, 4);
6913 calculateMacroscopicVariables(nghbrId, rho_m[2], u_m[2].data());
6914 }
6915 if(a_hasNeighbor(cellId, 5) && a_isActive(c_neighborId(cellId, 5))) {
6916 MInt nghbrId = c_neighborId(cellId, 5);
6917 calculateMacroscopicVariables(nghbrId, rho_p[2], u_p[2].data());
6918 }
6919 }
6920
6921 // Central difference in x-direction
6922 if((a_hasNeighbor(cellId, 0) && a_isActive(c_neighborId(cellId, 0)))
6923 && (a_hasNeighbor(cellId, 1) && a_isActive(c_neighborId(cellId, 1)))) {
6924 dudx = (rho_p[0] * u_p[0][0] - rho_m[0] * u_m[0][0]) / (2.0 * dx);
6925 }
6926 // Forwards differnce in x-direction
6927 else if((!a_hasNeighbor(cellId, 0) || !a_isActive(c_neighborId(cellId, 0)))
6928 && (a_hasNeighbor(cellId, 1) && a_isActive(c_neighborId(cellId, 1)))) {
6929 dudx = (rho_p[0] * u_p[0][0] - rho * u[0]) / dx;
6930 }
6931 // Backwards difference in x-direction
6932 else if((a_hasNeighbor(cellId, 0) && a_isActive(c_neighborId(cellId, 0)))
6933 && (!a_hasNeighbor(cellId, 1) || !a_isActive(c_neighborId(cellId, 1)))) {
6934 dudx = (rho * u[0] - rho_m[0] * u_m[0][0]) / dx;
6935 }
6936 // Central differences in y-direction
6937 if((a_hasNeighbor(cellId, 2) && a_isActive(c_neighborId(cellId, 2)))
6938 && (a_hasNeighbor(cellId, 3) && a_isActive(c_neighborId(cellId, 3)))) {
6939 dvdy = (rho_p[1] * u_p[1][1] - rho_m[1] * u_m[1][1]) / (2.0 * dx);
6940 }
6941 // Forwards differences in y-direction
6942 else if((!a_hasNeighbor(cellId, 2) || !a_isActive(c_neighborId(cellId, 2)))
6943 && (a_hasNeighbor(cellId, 3) && a_isActive(c_neighborId(cellId, 3)))) {
6944 dvdy = (rho_m[1] * u_p[1][1] - rho * u[1]) / dx;
6945 }
6946 // Backwars differences in y-direction
6947 else if((a_hasNeighbor(cellId, 2) && a_isActive(c_neighborId(cellId, 2)))
6948 && (!a_hasNeighbor(cellId, 3) || !a_isActive(c_neighborId(cellId, 3)))) {
6949 dvdy = (rho * u[1] - rho_m[1] * u_m[1][1]) / dx;
6950 }
6951 if constexpr(nDim == 3) {
6952 MFloat dwdz = 0.0;
6953 // Central differences in z-direction
6954 if((a_hasNeighbor(cellId, 4) && a_isActive(c_neighborId(cellId, 4)))
6955 && (a_hasNeighbor(cellId, 5) && a_isActive(c_neighborId(cellId, 5)))) {
6956 dwdz = (rho_p[2] * u_p[2][2] - rho_m[2] * u_m[2][2]) / (2.0 * dx);
6957 }
6958 // Forwards differences in z-direction
6959 else if((!a_hasNeighbor(cellId, 4) || !a_isActive(c_neighborId(cellId, 4)))
6960 && (a_hasNeighbor(cellId, 5) && a_isActive(c_neighborId(cellId, 5)))) {
6961 dwdz = (rho_p[2] * u_p[2][2] - rho * u[2]) / dx;
6962 }
6963 // Backwars differences in z-direction
6964 else if((a_hasNeighbor(cellId, 4) && a_isActive(c_neighborId(cellId, 4)))
6965 && (!a_hasNeighbor(cellId, 5) || !a_isActive(c_neighborId(cellId, 5)))) {
6966 dwdz = (rho * u[2] - rho_m[2] * u_m[2][2]) / dx;
6967 }
6968
6969 phi_m = abs(dudx + dvdy + dwdz) * pow(dx, cellSizeWeight_m);
6970 // Test: Do not use divergence but use gradient of solution!
6971 // phi_m = (abs(dudx)+abs(dvdy)+abs(dwdz))*pow(dx,2.0);
6972 }
6973 if constexpr(nDim == 2) phi_m = abs(dudx + dvdy) * pow(dx, cellSizeWeight_m);
6974
6975 sensors[sensorOffset + sen][gridId] = phi_m;
6976 sensorCellFlag[gridId][sensorOffset + sen] = 1;
6977 }
6978}
6979
6986template <MInt nDim, MInt nDist, class SysEqn>
6987void LbSolverDxQy<nDim, nDist, SysEqn>::sensorTotalPressure(std::vector<std::vector<MFloat>>& sensors,
6988 std::vector<std::bitset<64>>& sensorCellFlag,
6989 std::vector<MFloat>& sensorWeight, MInt sensorOffset,
6990 MInt sen) {
6991 m_log << " - Sensor preparation for the total pressure sensor" << endl;
6992 cerr0 << " - Sensor preparation for the total pressure sensor" << endl;
6993
6994 // Set sensor weights for refinement (K_f)
6995 sensorWeight[sensorOffset + sen] = this->m_sensorWeight[sen];
6996
6997 // Set cell seize weihts
6998 // TODO labels:LB Make available by property?
6999 MFloat cellSizeWeight_p = 1.0;
7000
7001 for(MInt cellId = 0; cellId < noInternalCells(); cellId++) {
7002 ASSERT(!a_isHalo(cellId), "");
7003 const MInt gridId = this->grid().tree().solver2grid(cellId);
7004
7005 // Mesh adaptation is only performed on active cells
7006 // --> untag inactive cells
7007 if(!a_isActive(cellId)) {
7008 sensorCellFlag[gridId][sensorOffset + sen] = 0;
7009 continue;
7010 }
7011
7012 // Get cell size for cell size weighting
7013 const MFloat dx = grid().cellLengthAtLevel(c_level(cellId));
7014
7015 // Compute macroscopic variables for sensor evaluation
7016 // All cells performed propagation step before. Thus, in-coming distributions
7017 // of all cells are in the same time step and comparable
7018 // --> Compute macroscopic variables from in-coming distributions.
7019 //
7020 // Depending on the neighbors of the cell, variables for
7021 // central, backwards or forwards differentials are computed
7022 MFloat rho{};
7023 std::array<MFloat, nDim> u{};
7024 calculateMacroscopicVariables(cellId, rho, u.data());
7025
7026 // (1) Difference in total pressure
7027 // Incident flow total pressure depends on bc!
7028 // Here so far only for bc10000 --> Assume rho=1 on boundary.
7029 const MFloat rho_0 = 1.0;
7030 const MFloat p_0 = rho_0 / 3.0;
7031 const MFloat p = rho / 3.0;
7032 const MFloat pTotal_0 = 0.5 * rho_0 * (m_Ma * LBCS) * (m_Ma * LBCS) + p_0;
7033 const MFloat squaredVelocity = std::inner_product(u.begin(), u.end(), u.begin(), 0.0);
7034 const MFloat pTotal = 0.5 * rho * squaredVelocity + p;
7035 const MFloat phi_p = abs(pTotal_0 - pTotal) * pow(dx, cellSizeWeight_p);
7036 sensors[sensorOffset + sen][gridId] = phi_p;
7037 sensorCellFlag[gridId][sensorOffset + sen] = 1;
7038 }
7039}
7040
7048// TODO: EXPERIMENTAL, should be reworked!
7049template <MInt nDim, MInt nDist, class SysEqn>
7050void LbSolverDxQy<nDim, nDist, SysEqn>::sensorMeanStress(std::vector<std::vector<MFloat>>& sensors,
7051 std::vector<std::bitset<64>>& sensorCellFlag,
7052 std::vector<MFloat>& sensorWeight, MInt sensorOffset,
7053 MInt sen) {
7054 if(nDim == 3) {
7055 TERMM(1, "Not implemented for 3D");
7056 }
7057
7058
7059 m_log << " - Sensor preparation for the mean stress sensor" << endl;
7060 cerr0 << " - Sensor preparation for the mean stress sensor" << endl;
7061
7062 // Set sensor weights for refinement (K_f)
7063 sensorWeight[sensorOffset + sen] = this->m_sensorWeight[sen];
7064
7065 // Set cell seize weihts
7066 // TODO: Make available by property?
7067 const MFloat cellSizeWeight = 1.0;
7068
7069 for(MInt cellId = 0; cellId < noInternalCells(); cellId++) {
7070 ASSERT(!a_isHalo(cellId), "");
7071 const MInt gridId = this->grid().tree().solver2grid(cellId);
7072
7073 // Mesh adaptation is only performed on active cells
7074 // --> untag inactive cells
7075 if(!a_isActive(cellId)) {
7076 sensorCellFlag[gridId][sensorOffset + sen] = 0;
7077 continue;
7078 }
7079
7080 // Calculate mean stress
7081 const MFloat rho = a_variable(cellId, PV->RHO);
7082 std::array<MFloat, 2> u = {a_variable(cellId, PV->U), a_variable(cellId, PV->V)};
7083
7084 std::array<MFloat, nDist> eqDist{};
7085 eqDist = getEqDists(rho, u.data());
7086
7087 // Calculation of non-eq-parts
7088 std::array<MFloat, 9> d{};
7089 for(MInt j = 0; j < 9; j++) {
7090 d[j] = a_oldDistribution(cellId, j) - eqDist[j];
7091 }
7092
7093 // Calculation of momentum flux tensor for non-equilibrium parts
7094 std::array<MFloat, 4> Q{};
7095 Q[0] = (d[0] + d[1] + d[4] + d[5] + d[6] + d[7]);
7096 Q[1] = (d[4] - d[5] + d[6] - d[7]);
7097
7098 Q[2] = Q[1];
7099 Q[3] = (d[2] + d[3] + d[4] + d[5] + d[6] + d[7]);
7100
7101 MFloat Qmean = 0.0;
7102 for(MInt k = 0; k < 4; k++) {
7103 Qmean += Q[k] * Q[k];
7104 }
7105
7106 Qmean = sqrt(2 * Qmean);
7107
7108 // Get cell size for cell size weighting
7109 const MFloat dx = grid().cellLengthAtLevel(c_level(cellId));
7110
7111 const MFloat phi = Qmean * pow(dx, cellSizeWeight);
7112
7113 sensors[sensorOffset + sen][gridId] = phi;
7114 sensorCellFlag[gridId][sensorOffset + sen] = 1;
7115 }
7116}
7117
7122template <MInt nDim, MInt nDist, class SysEqn>
7124 if(m_isRefined || this->m_adaptation) {
7125 delete m_interface;
7126 }
7127
7128 if(m_isRefined || this->m_adaptation) m_interface = new LbInterfaceDxQy<nDim, nDist, SysEqn>(this);
7129
7130 delete m_bndCnd;
7131 m_bndCnd = new LbBndCnd(this);
7132 LbSolver<nDim>::m_bndCnd = m_bndCnd;
7133 m_bndCnd->initializeBcData();
7134}
7135
7136template <MInt nDim, MInt nDist, class SysEqn>
7138 TRACE();
7139
7140 // TODO labels:LB Unify for 2D/3D (as far as possible).
7141
7142 if constexpr(nDim == 3) {
7143 MInt startSet = this->m_levelSetId;
7144 static constexpr MInt maxNoDistributions = IPOW3[nDim];
7145 static constexpr MInt firstCornerDist = 18;
7146 static constexpr MInt firstEdgeDist = 6;
7147 static constexpr MInt noEdges = 12;
7148
7149 // TODO labels:LB Use lattice descriptor.
7150
7151 static constexpr MInt lb_CornerMappingForSurfaces[6][4] = {{18, 19, 20, 21}, {22, 23, 24, 25}, {18, 19, 22, 23},
7152 {20, 21, 24, 25}, {18, 20, 22, 24}, {19, 21, 23, 25}};
7153
7154 static constexpr MInt lb_CornerMappingForEdges[12][2] = {{18, 19}, {20, 21}, {22, 23}, {24, 25},
7155 {18, 20}, {19, 21}, {22, 24}, {23, 25},
7156 {18, 22}, {19, 23}, {20, 24}, {21, 25}};
7157
7158 static constexpr MInt lb_geomIntersToLb[8] = {0, 4, 2, 6, 1, 5, 3, 7};
7159
7160 static constexpr MFloat factor[26] = {F1, F1, F1, F1, F1, F1, SQRT2, SQRT2, SQRT2,
7161 SQRT2, SQRT2, SQRT2, SQRT2, SQRT2, SQRT2, SQRT2, SQRT2, SQRT2,
7162 SQRT3, SQRT3, SQRT3, SQRT3, SQRT3, SQRT3, SQRT3, SQRT3};
7163
7164 // 1. Get the nodal Ls values form the CutCandidates Class
7165 // 2. Find the Cut Cells and calculate the missing Ls values
7166 // at the cell surfaces and cell edges for those
7167 // 3. Calculate the Wall distances
7168 this->m_currentNoG0Cells = 0;
7169 m_bndCnd->m_boundaryCellsMb.noDistances(nDist - 1);
7170 m_bndCnd->m_boundaryCellsMb.reset(this->m_noG0CandidatesTotal);
7171 m_bndCnd->m_boundaryCellMappingMb.clear();
7172
7173 for(MInt candidate = 0; candidate < this->m_noG0CandidatesTotal; candidate++) {
7174 for(MInt set = startSet; set < this->m_maxNoSets; set++) {
7175 const MInt arrayPosNGV = set * (maxNoDistributions - 1);
7176 for(MInt i = 0; i < IPOW2(nDim); i++) {
7177 this->m_nodalGValues[candidate][arrayPosNGV + firstCornerDist + lb_geomIntersToLb[i]] =
7178 this->m_G0Candidates[candidate].nodalValues[set][i];
7179 }
7180
7181 // Step a: Find Edges with a cut, i.e. the nodes of the edge have opposite signs in m_nodalGValues
7182 MInt edgeCounter = 0;
7183 for(MInt edge = 0; edge < noEdges; edge++) {
7184 MFloat edgeGValue = this->m_nodalGValues[candidate][arrayPosNGV + Ld::nodalConnectivityVector(edge, 0)]
7185 * this->m_nodalGValues[candidate][arrayPosNGV + Ld::nodalConnectivityVector(edge, 1)];
7186
7187 if(edgeGValue < 0) edgeCounter++;
7188 }
7189
7190 // Step b: If there are less than two cuts for a G0Candidate it is not a G0 Cell. Skip that cell!!
7191 const MInt pCellId = this->m_G0Candidates[candidate].cellId;
7192 const MInt actualSet = set - startSet;
7193 if(edgeCounter < 2) {
7194 this->a_isG0CandidateOfSet(pCellId, actualSet) = false;
7195 continue;
7196 } else {
7197 this->a_isG0CandidateOfSet(pCellId, actualSet) = true;
7198 this->m_G0CellMapping[pCellId] = this->m_currentNoG0Cells;
7199 // Use new mapping in bndCnd
7200 m_bndCnd->m_boundaryCellMappingMb[pCellId] = this->m_currentNoG0Cells;
7201 }
7202
7203 // Add relevant information to G0 boundary cell collector
7204 // Cell is a G0 boundary cell
7205 const MInt boundaryCellId = m_bndCnd->m_boundaryCellsMb.size();
7206 m_bndCnd->m_boundaryCellsMb.append();
7207 m_bndCnd->m_boundaryCellsMb.cellId(boundaryCellId) = pCellId;
7208
7209 // Step c: Calculate the missing Ls values at the cell surfaces and cell edges
7210 this->m_G0CellList[this->m_currentNoG0Cells] = pCellId;
7211 for(MInt dist = 0; dist < firstEdgeDist; dist++) {
7212 for(MInt i = 0; i < 4; i++) {
7213 this->m_nodalGValues[candidate][arrayPosNGV + dist] +=
7214 this->m_nodalGValues[candidate][arrayPosNGV + lb_CornerMappingForSurfaces[dist][i]];
7215 }
7216 this->m_nodalGValues[candidate][arrayPosNGV + dist] /= F4;
7217 }
7218 for(MInt dist = firstEdgeDist; dist < firstCornerDist; dist++) {
7219 for(MInt i = 0; i < 2; i++) {
7220 this->m_nodalGValues[candidate][arrayPosNGV + dist] +=
7221 this->m_nodalGValues[candidate][arrayPosNGV + lb_CornerMappingForEdges[dist - firstEdgeDist][i]];
7222 }
7223 this->m_nodalGValues[candidate][arrayPosNGV + dist] /= F2;
7224 }
7225
7226
7227 MInt arrayPosWallDists = (set - startSet) * (nDist - 1);
7228 // Step d: Check which distributions are cutted and calculate the Wall distance for those
7229 for(MInt dir = 0; dir < nDist - 1; dir++) {
7230 if((this->a_levelSetFunctionMB(pCellId, set) * this->m_nodalGValues[candidate][arrayPosNGV + dir]) > 0) {
7231 // TODO labels:LB Remove offset and use set as third index ...
7232 m_bndCnd->m_boundaryCellsMb.distance(boundaryCellId, arrayPosWallDists + dir) = F2;
7233 } else {
7234 MFloat levelSetRatio =
7235 abs(this->m_nodalGValues[candidate][arrayPosNGV + dir] / this->a_levelSetFunctionMB(pCellId, set));
7236 MFloat cellLength = this->c_cellLengthAtLevel(this->a_level(pCellId)) * F1B2 * factor[dir];
7237 m_bndCnd->m_boundaryCellsMb.distance(boundaryCellId, arrayPosWallDists + dir) =
7238 cellLength / (levelSetRatio + F1);
7239 }
7240
7241 // Determine surface center
7242 // TODO labels:LB Fix very bad estimate by boundary cell center using approx normal (minWallDist)
7243 for(MInt n = 0; n < nDim; n++) {
7244 m_bndCnd->m_boundaryCellsMb.surfaceCenter(boundaryCellId, dir, n) =
7245 a_coordinate(pCellId, n)
7246 + m_bndCnd->m_boundaryCellsMb.distance(boundaryCellId, dir) * Ld::ppdfDir(dir, n) * 1 / factor[dir];
7247 }
7248 }
7249 for(MInt n = 0; n < nDim; n++) {
7250 m_bndCnd->m_boundaryCellsMb.cellCenter(boundaryCellId, n) = a_coordinate(pCellId, n);
7251 }
7252
7253 this->m_currentNoG0Cells++;
7254 }
7255 }
7256 } else {
7257 // D2Q9 Stencil for Cut Cells including the edges:
7258 //
7259 // 14 15
7260 // 7 -- 3 -- 4
7261 // |\ | /|
7262 // 9 | \ | / | 11
7263 // | \ | / |
7264 // 0 -- * -- 1
7265 // | / | \ |
7266 // 8 | / | \ | 10
7267 // |/ | \|
7268 // 6 -- 2 -- 5
7269 // 12 13
7270 //
7271 // 1. Get the nodal Ls values form the CutCandidates Class
7272 // m_nodelGValues holds the LS values for each candidate in the order of the distributions for each set
7273
7274 // 2. Find the Cut Cells by multipling the nodal LS values of the 4 corners
7275 // If the two LS values have opposite signs the edge has a cut if the product is exaktly 0 the cell has to
7276 // be considered, since it is still a boundary cell.
7277 // Furthermore, the cutPoints are calculated for all edges with a cut. The eges are seperated in two part
7278 // which is needed for the calculation of the cut cell volume fraction
7279
7280 // 3. Calculate the missing Ls values at the cell surfaces and cell edges for the cut cells
7281 // by calculating the mean values of the surrounding corners.
7282
7283 // 4. Calculate the Wall distances using the formular x2 = cellLength / (1 + LS2/LS1)
7284
7285 const MInt startSet = this->m_levelSetId;
7286 constexpr MInt maxNoDistributions = 9;
7287 constexpr MInt firstCornerDist = 4;
7288 constexpr MInt noEdges = 4;
7289 // 1. Get the nodal Ls values form the CutCandidates Class
7290 // 2. Find the Cut Cells and calculate the missing Ls values
7291 // at the cell surfaces and cell edges for those
7292 // 3. Calculate the Wall distances
7293 m_bndCnd->m_boundaryCellsMb.noDistances(nDist - 1);
7294 m_bndCnd->m_boundaryCellsMb.reset(this->m_noG0CandidatesTotal);
7295 constexpr MInt lb_CornerMappingForEdges[4][2] = {{6, 7}, {4, 5}, {5, 6}, {7, 4}};
7296 constexpr MFloat factor[8] = {F1, F1, F1, F1, SQRT2, SQRT2, SQRT2, SQRT2};
7297 // 1. Get the nodal Ls values form the CutCandidates Class
7298 // 2. Find the Cut Cells and calculate the missing Ls values
7299 // at the cell surfaces and cell edges for those
7300 // 3. Calculate the Wall distances
7301
7302 // Reset data structure
7303 this->m_currentNoG0Cells = 0;
7304 m_bndCnd->m_boundaryCellsMb.noDistances(nDist - 1);
7305 m_bndCnd->m_boundaryCellsMb.reset(this->m_noG0CandidatesTotal);
7306 m_bndCnd->m_boundaryCellMappingMb.clear();
7307
7308 for(MInt candidate = 0; candidate < this->m_noG0CandidatesTotal; candidate++) {
7309 for(MInt set = startSet; set < this->m_maxNoSets; set++) {
7310 MInt arrayPosNGV = set * (maxNoDistributions - 1);
7311 this->m_nodalGValues[candidate][arrayPosNGV + firstCornerDist + 2] =
7312 this->m_G0Candidates[candidate].nodalValues[set][0];
7313 this->m_nodalGValues[candidate][arrayPosNGV + firstCornerDist + 1] =
7314 this->m_G0Candidates[candidate].nodalValues[set][1];
7315 this->m_nodalGValues[candidate][arrayPosNGV + firstCornerDist + 3] =
7316 this->m_G0Candidates[candidate].nodalValues[set][2];
7317 this->m_nodalGValues[candidate][arrayPosNGV + firstCornerDist + 0] =
7318 this->m_G0Candidates[candidate].nodalValues[set][3];
7319
7320 // Step a: Find Edges with a cut,
7321 // i.e. the nodes of the edge have opposite signs in m_nodalGValues
7322 MInt edgeCounter = 0;
7323 for(MInt edge = 0; edge < noEdges; edge++) {
7324 MFloat edgeGValue = this->m_nodalGValues[candidate][arrayPosNGV + Ld::nodalConnectivityVector(edge, 0)]
7325 * this->m_nodalGValues[candidate][arrayPosNGV + Ld::nodalConnectivityVector(edge, 1)];
7326 if(edgeGValue <= 0) edgeCounter++;
7327 }
7328
7329 // Step b: If there are less than two cuts for a G0Candidate it is not a G0 Cell.
7330 // Skip that cell!!
7331 MInt pCellId = this->m_G0Candidates[candidate].cellId;
7332 MInt actualSet = set - startSet;
7333 if(edgeCounter < 2) {
7334 this->a_isG0CandidateOfSet(pCellId, actualSet) = false;
7335 continue;
7336 } else {
7337 this->a_isG0CandidateOfSet(pCellId, actualSet) = true;
7338 this->m_G0CellMapping[pCellId] = this->m_currentNoG0Cells;
7339 // Use new mapping in bndCnd
7340 m_bndCnd->m_boundaryCellMappingMb[pCellId] = this->m_currentNoG0Cells;
7341 }
7342
7343 // Add relevant information to G0 boundary cell collector
7344 // Cell is a G0 boundary cell
7345 const MInt boundaryCellId = m_bndCnd->m_boundaryCellsMb.size();
7346 m_bndCnd->m_boundaryCellsMb.append();
7347 m_bndCnd->m_boundaryCellsMb.cellId(boundaryCellId) = pCellId;
7348
7349 // Step c: Calculate the missing Ls values at the cell edges
7350 this->m_G0CellList[this->m_currentNoG0Cells] = pCellId;
7351 for(MInt dist = 0; dist < firstCornerDist; dist++) {
7352 for(MInt i = 0; i < 2; i++) {
7353 this->m_nodalGValues[candidate][arrayPosNGV + dist] +=
7354 this->m_nodalGValues[candidate][arrayPosNGV + lb_CornerMappingForEdges[dist][i]];
7355 }
7356 this->m_nodalGValues[candidate][arrayPosNGV + dist] /= F2;
7357 }
7358
7359 MInt arrayPosWallDists = (set - startSet) * (nDist - 1);
7360 // Step d: Check which distributions are cutted and calculate the Wall distance for those
7361 for(MInt dir = 0; dir < nDist - 1; dir++) {
7362 if((this->a_levelSetFunctionMB(pCellId, set) * this->m_nodalGValues[candidate][arrayPosNGV + dir]) > 0) {
7363 // TODO labels:LB Remove offset and use set as third index ...
7364 m_bndCnd->m_boundaryCellsMb.distance(boundaryCellId, arrayPosWallDists + dir) = F2;
7365 } else {
7366 const MFloat levelSetRatio =
7367 abs(this->m_nodalGValues[candidate][arrayPosNGV + dir] / this->a_levelSetFunctionMB(pCellId, set));
7368 const MFloat cellLength = this->c_cellLengthAtLevel(this->a_level(pCellId)) * F1B2 * factor[dir];
7369 // TODO labels:LB Remove offset and use set as third index ...
7370 m_bndCnd->m_boundaryCellsMb.distance(boundaryCellId, arrayPosWallDists + dir) =
7371 cellLength / (levelSetRatio + F1);
7372 }
7373
7374 // Determine surface center
7375 // TODO labels:LB Fix very bad estimate by boundary cell center using approx normal (minWallDist)
7376 // OR: Store cross-over point of every cut-direction to make the
7377 // angular momentum exchange even better!
7378 for(MInt n = 0; n < nDim; n++) {
7379 m_bndCnd->m_boundaryCellsMb.surfaceCenter(boundaryCellId, dir, n) =
7380 a_coordinate(pCellId, n)
7381 + m_bndCnd->m_boundaryCellsMb.distance(boundaryCellId, n) * Ld::ppdfDir(dir, n) * 1 / factor[dir];
7382 }
7383 }
7384 for(MInt n = 0; n < nDim; n++) {
7385 m_bndCnd->m_boundaryCellsMb.cellCenter(boundaryCellId, n) = a_coordinate(pCellId, n);
7386 }
7387
7388 this->m_currentNoG0Cells++;
7389 }
7390 }
7391 }
7392}
7393
7394template <MInt nDim, MInt nDist, class SysEqn>
7396 TRACE();
7397
7398 if(globalTimeStep % m_residualInterval == 0) {
7399 calculateResidual();
7400 }
7401
7402 return true;
7403}
7404
7412template <MInt nDim, MInt nDist, class SysEqn>
7414 TRACE();
7415
7416 /*********************************************/
7417 /* 2D LAMINAR CHANNEL INITIALIZATION */
7418 /* m_referenceLength must be channel half width !!! */
7419 /* Ma refers to velocity on centerline !!! */
7420 /*********************************************/
7421 if(string2enum(m_initMethod) == LB_LAMINAR_CHANNEL_INIT) {
7422 // Re must be defined for channel half height
7423
7424 m_nu = m_Ma * LBCS / m_Re * m_referenceLength;
7425
7426 m_densityGradient = m_Ma * LBCS * 9.0 * m_nu / (m_referenceLength * m_referenceLength);
7427
7428 constexpr MInt dir = 0;
7429 for(MInt mi = 0; mi < Ld::dxQyFld(); mi++) {
7430 m_Fext[Ld::nFld(dir, mi)] = Ld::tp(Ld::distType(mi)) * -1.0 * m_densityGradient;
7431 m_Fext[Ld::pFld(dir, mi)] = Ld::tp(Ld::distType(mi)) * 1.0 * m_densityGradient;
7432 }
7433 }
7434
7435 /*********************************************/
7436 /* TURBULENT CHANNEL INITIALIZATION */
7437 /* m_referenceLength must be channel half width !!! */
7438 /* Ma refers to velocity on centerline !!! */
7439 /*********************************************/
7440 if(string2enum(m_initMethod) == LB_TURBULENT_CHANNEL_INIT) {
7441 // For now testing only the D3Q19 algorithm
7442 MFloat uTau;
7443
7444 // Re must be defined for channel half width
7445 m_nu = m_Ma * LBCS / m_Re * m_referenceLength;
7446 uTau = (MFloat)m_ReTau * m_nu / m_referenceLength;
7447
7448 // The ratio between the turb. channel length and channel half width : ratio = L/H
7449 // MFloat ratio = m_domainLength/m_referenceLength;
7450
7451 m_densityGradient = 3.0 * uTau * uTau / m_referenceLength;
7452
7453 constexpr MInt dir = 0;
7454 for(MInt mi = 0; mi < Ld::dxQyFld(); mi++) {
7455 m_Fext[Ld::nFld(dir, mi)] = Ld::tp(Ld::distType(mi)) * -1.0 * m_densityGradient;
7456 m_Fext[Ld::pFld(dir, mi)] = Ld::tp(Ld::distType(mi)) * 1.0 * m_densityGradient;
7457 }
7458 }
7459
7460 /**************************************/
7461 /* TURBULENT DUCT INITIALIZATION */
7462 /**************************************/
7463 if(string2enum(m_initMethod) == LB_TURBULENT_DUCT_INIT) {
7464 // For now testing only the D3Q19 algorithm
7465 MFloat uTau;
7466
7467 uTau = (MFloat)m_ReTau / m_Re * m_Ma * LBCS;
7468 MFloat ratio = m_domainLength / (m_referenceLength * F1B2);
7469
7470 m_densityGradient = 3.0 * uTau * uTau * ratio / m_domainLength;
7471
7472 constexpr MInt dir = 0;
7473 for(MInt mi = 0; mi < Ld::dxQyFld(); mi++) {
7474 m_Fext[Ld::nFld(dir, mi)] = Ld::tp(Ld::distType(mi)) * -1.0 * m_densityGradient;
7475 m_Fext[Ld::pFld(dir, mi)] = Ld::tp(Ld::distType(mi)) * 1.0 * m_densityGradient;
7476 }
7477 }
7478
7479 /*************************************************/
7480 /* TURBULENT PIPE INITIALIZATION */
7481 /* m_referenceLength must be pipe diameter !!! */
7482 /* Ma refers to the maximum streamwise velocity !!! */
7483 /* u_mean = 0.816 * u_max */
7484 /*************************************************/
7485 if(string2enum(m_initMethod) == LB_TURBULENT_PIPE_INIT) {
7486 // For now testing only the D3Q19 algorithm
7487 MFloat uTau;
7488
7489 // uTau = (MFloat)m_ReTau/m_Re * m_Ma * LBCS ;
7490 m_nu = m_Ma * LBCS / m_Re * m_referenceLength;
7491 uTau = (MFloat)m_ReTau * m_nu / m_referenceLength;
7492
7493 /*
7494 MFloat ratio = m_domainLength/m_referenceLength;
7495 // pressure drop over entire length according to Blasius law (IN THIS CASE Ma DEFINES THE MEAN VELOCITY!)
7496 m_gradient = 0.3164 * pow(m_Re,-0.25) * ratio * (m_Ma*LBCS) * (m_Ma*LBCS) / 2;//rho=1
7497 */
7498
7499 // density drop per cell
7500 m_densityGradient = 3.0 * 2.0 * uTau * uTau / (F1B2 * m_referenceLength); // Pope, p.293
7501
7502 if constexpr(nDim != 3) {
7503 std::stringstream ss;
7504 ss << "Init method " << m_initMethod << " is only available for 3D." << std::endl;
7505 TERMM(1, ss.str());
7506 }
7507 constexpr MInt dir = 2;
7508 for(MInt mi = 0; mi < Ld::dxQyFld(); mi++) {
7509 m_Fext[Ld::nFld(dir, mi)] = Ld::tp(Ld::distType(mi)) * -1.0 * m_densityGradient;
7510 m_Fext[Ld::pFld(dir, mi)] = Ld::tp(Ld::distType(mi)) * 1.0 * m_densityGradient;
7511 }
7512 }
7513
7514 /*******************************/
7515 /* LAMINAR PIPE INITIALIZATION */
7516 /*******************************/
7517 if(string2enum(m_initMethod) == LB_LAMINAR_PIPE_INIT) {
7518 m_nu = m_Ma * LBCS / m_Re * m_referenceLength;
7519
7520 // law of Hagen Poiseuille
7521 // The pressure gradient is one third of the density gradient !
7522 // m_gradient = 3*F1B2*(m_Ma*LBCS)*m_domainLength/m_referenceLength/m_referenceLength*64.0*m_nu;
7523 m_densityGradient =
7524 3.0 * 8.0 * (m_Ma * LBCS) * m_nu / ((F1B2 * m_referenceLength) * (F1B2 * m_referenceLength)); // rho=1
7525
7526 if constexpr(nDim != 3) {
7527 std::stringstream ss;
7528 ss << "Init method " << m_initMethod << " is only available for 3D." << std::endl;
7529 TERMM(1, ss.str());
7530 }
7531 constexpr MInt dir = 2;
7532 for(MInt mi = 0; mi < Ld::dxQyFld(); mi++) {
7533 m_Fext[Ld::nFld(dir, mi)] = Ld::tp(Ld::distType(mi)) * -1.0 * m_densityGradient;
7534 m_Fext[Ld::pFld(dir, mi)] = Ld::tp(Ld::distType(mi)) * 1.0 * m_densityGradient;
7535 }
7536 }
7537}
7538
7539template <MInt nDim, MInt nDist, class SysEqn>
7541 static MBool firstCall = true;
7542 static MFloat origFext[nDist];
7543 if(firstCall) {
7544 // save the incoming m_Fext to recall them at re-initializations triggered by velocity control
7545 firstCall = false;
7546 for(MInt i = 0; i < nDist; i++) {
7547 origFext[i] = m_Fext[i];
7548 }
7549 }
7550 for(MInt dir = 0; dir < nDim; dir++) {
7551 for(MInt mi = 0; mi < Ld::dxQyFld(); mi++) {
7552 m_Fext[Ld::nFld(dir, mi)] =
7553 origFext[Ld::nFld(dir, mi)] + Ld::tp(Ld::distType(Ld::nFld(dir, mi))) * -1.0 * m_volumeAccel[dir] * 3.0;
7554 m_Fext[Ld::pFld(dir, mi)] =
7555 origFext[Ld::pFld(dir, mi)] + Ld::tp(Ld::distType(Ld::pFld(dir, mi))) * 1.0 * m_volumeAccel[dir] * 3.0;
7556 }
7557 }
7558
7559 if(m_isEELiquid) {
7560 for(MInt dir = 0; dir < nDim; dir++) {
7561 for(MInt mi = 0; mi < Ld::dxQyFld(); mi++) {
7562 m_EELiquid.Fg[Ld::nFld(dir, mi)] =
7563 Ld::tp(Ld::distType(Ld::nFld(dir, mi))) * -1.0 * m_EELiquid.gravityAccelM[dir] * 3.0;
7564 m_EELiquid.Fg[Ld::pFld(dir, mi)] =
7565 Ld::tp(Ld::distType(Ld::pFld(dir, mi))) * 1.0 * m_EELiquid.gravityAccelM[dir] * 3.0;
7566 }
7567 }
7568 }
7569}
7570
7584template <MInt nDim, MInt nDist, class SysEqn>
7585template <MBool compressible>
7587 TRACE();
7588 // Required for ported functions, since GPUs cannot access the global variable globalTimeStep
7589 const MInt gTS = globalTimeStep;
7590
7591 maia::parallelFor<true>(0, m_currentMaxNoCells, [=](MInt i) {
7592 const MInt pCellId = m_activeCellList[i];
7593 const MInt lvlDiff = maxLevel() - c_level(pCellId);
7594 if((gTS) % IPOW2(lvlDiff) != 0) return;
7595 // In the following step only rho is updated while u is kept
7596 // constant with its initial state u0.
7597 // 1) Calculate rho, rho*u and the associated f_eq(rho, u)
7598#ifdef WAR_NVHPC_PSTL
7599 MFloat u[nDim] = {F0};
7600 for(MInt d = 0; d < nDim; d++) {
7601 u[d] = a_variable(pCellId, d);
7602 }
7603 calculateMacroscopicVariables<compressible>(pCellId, a_variable(pCellId, PV->RHO), u);
7604 for(MInt d = 0; d < nDim; d++) {
7605 a_variable(pCellId, d) = u[d];
7606 }
7607#else
7608 calculateMacroscopicVariables<compressible>(pCellId, a_variable(pCellId, PV->RHO), &a_variable(pCellId, PV->U));
7609#endif
7610 MFloat eqDist[nDist], trgEqDist[nDist];
7611#ifdef WAR_NVHPC_PSTL
7612 for(MInt d = 0; d < nDim; d++) {
7613 u[d] = a_variable(pCellId, d);
7614 }
7615 sysEqn().calcEqDists(a_variable(pCellId, PV->RHO), u, &eqDist[0], m_mFld1.data(), m_mFld2.data(), m_tp.data(),
7616 m_distFld.data());
7617#else
7618 sysEqn().calcEqDists(a_variable(pCellId, PV->RHO), &a_variable(pCellId, PV->U), &eqDist[0]);
7619#endif
7620 // 2) Set state to (rho, u0) and calculate associated f_eq(rho, u0)
7621 for(MInt d = 0; d < nDim; d++) {
7622 a_variable(pCellId, PV->U + d) = a_oldVariable(pCellId, PV->U + d);
7623 }
7624#ifdef WAR_NVHPC_PSTL
7625 for(MInt d = 0; d < nDim; d++) {
7626 u[d] = a_variable(pCellId, d);
7627 }
7628 sysEqn().calcEqDists(a_variable(pCellId, PV->RHO), u, &trgEqDist[0], m_mFld1.data(), m_mFld2.data(), m_tp.data(),
7629 m_distFld.data());
7630#else
7631 sysEqn().calcEqDists(a_variable(pCellId, PV->RHO), &a_variable(pCellId, PV->U), &trgEqDist[0]);
7632#endif
7633 // 3) Reset f such that: f_new = f_eq(rho, u0) + f_neq(rho, u)
7634 for(MInt j = 0; j < nDist; j++) {
7635 a_oldDistribution(pCellId, j) = a_oldDistribution(pCellId, j) + trgEqDist[j] - eqDist[j];
7636 }
7637 });
7638}
7639
7640template <MInt nDim, MInt nDist, class SysEqn>
7642 if(this->isCompressible()) {
7643 initRunCorrection_<true>();
7644 } else {
7645 initRunCorrection_<false>();
7646 }
7647}
7648
7659template <MInt nDim, MInt nDist, class SysEqn>
7661 TRACE();
7662
7663 MInt xPos, yPos, zPos;
7664 MInt lx = 0, ly = 0, lz = 0;
7665
7666 // fft-domain dimensions
7667 // this holds the size of the domain in number of cells on lowest level
7668 lx = m_arraySize[0] / FPOW2(maxLevel() - minLevel());
7669 ly = m_arraySize[1] / FPOW2(maxLevel() - minLevel());
7670 if(nDim == 3) lz = m_arraySize[2] / FPOW2(maxLevel() - minLevel());
7671
7672 fftw_complex *uPhysField, *vPhysField, *wPhysField;
7673
7674 // field of velocities from positve frequencies
7675 uPhysField = (fftw_complex*)fftw_malloc(lx * ly * lz * sizeof(fftw_complex));
7676 vPhysField = (fftw_complex*)fftw_malloc(lx * ly * lz * sizeof(fftw_complex));
7677 wPhysField = (fftw_complex*)fftw_malloc(lx * ly * lz * sizeof(fftw_complex));
7678
7679 // in multisolver mode the velocity field is created in solver 0 and broadcasted to all others
7680 ScratchSpace<MFloat> sendRecvBufferU(lx * ly * lz, AT_, "sendRecvBufferU");
7681 ScratchSpace<MFloat> sendRecvBufferV(lx * ly * lz, AT_, "sendRecvBufferV");
7682 ScratchSpace<MFloat> sendRecvBufferW(lx * ly * lz, AT_, "sendRecvBufferW");
7683
7684 if(domainId() == 0) {
7685 // create velocity field
7686 maia::math::initFft(uPhysField, vPhysField, wPhysField, lx, ly, lz, m_noPeakModes, m_Ma);
7687
7688 // copy values to buffer
7689 for(MInt p = 0; p < lx; p++) {
7690 for(MInt q = 0; q < ly; q++) {
7691 for(MInt r = 0; r < lz; r++) {
7692 sendRecvBufferU[r + lz * (q + ly * p)] = uPhysField[r + lz * (q + ly * p)][0];
7693 sendRecvBufferV[r + lz * (q + ly * p)] = vPhysField[r + lz * (q + ly * p)][0];
7694 sendRecvBufferW[r + lz * (q + ly * p)] = wPhysField[r + lz * (q + ly * p)][0];
7695 }
7696 }
7697 }
7698 }
7699
7700 MPI_Bcast(&sendRecvBufferU[0], lx * ly * lz, MPI_DOUBLE, 0, mpiComm(), AT_, "sendRecvBufferU[0]");
7701 MPI_Bcast(&sendRecvBufferV[0], lx * ly * lz, MPI_DOUBLE, 0, mpiComm(), AT_, "sendRecvBufferV[0]");
7702 MPI_Bcast(&sendRecvBufferW[0], lx * ly * lz, MPI_DOUBLE, 0, mpiComm(), AT_, "sendRecvBufferW[0]");
7703
7704 if(domainId() != 0) {
7705 // copy values from buffer
7706 for(MInt p = 0; p < lx; p++) {
7707 for(MInt q = 0; q < ly; q++) {
7708 for(MInt r = 0; r < lz; r++) {
7709 uPhysField[r + lz * (q + ly * p)][0] = sendRecvBufferU[r + lz * (q + ly * p)];
7710 vPhysField[r + lz * (q + ly * p)][0] = sendRecvBufferV[r + lz * (q + ly * p)];
7711 wPhysField[r + lz * (q + ly * p)][0] = sendRecvBufferW[r + lz * (q + ly * p)];
7712 }
7713 }
7714 }
7715 }
7716
7717 MFloat actualCellLength;
7718 MFloat rho, u[3] = {0.0, 0.0, 0.0}, uTau, yPlus;
7719
7720 // all cells have the same density
7721 if(m_densityFluctuations)
7722 rho = 0.0;
7723 else
7724 rho = 1.0;
7725
7726 uTau = (MFloat)m_ReTau * m_nu / m_referenceLength;
7727
7728 // tmpwidth equals diameter(in cells) * cellLength on maxLevel
7729 // diameter is half the channel height!
7730 MFloat tmpWidth = m_referenceLength * m_smallestCellLength;
7731 // tmpWidth = 0.5 * fabs(bBox[4]-bBox[1]);
7732
7733 cerr << " --- prescribing mean velocity profile for turbulent channel ---" << endl;
7734 for(MInt i = 0; i < a_noCells(); i++) {
7735 initNu(i, m_nu);
7736
7737 yPlus = m_ReTau * (1.0 - fabs(a_coordinate(i, 1)) / tmpWidth);
7738
7739 // debug:
7740 if(yPlus < 0 || yPlus > m_ReTau) {
7741 stringstream errorMessage;
7742 errorMessage << "incorrect value for yPlus: " << yPlus << " exiting...";
7743 TERMM(1, errorMessage.str());
7744 }
7745
7746 // set the mean velocity profile
7747 if(yPlus <= 5.0) {
7748 u[0] = uTau * yPlus;
7749 } else {
7750 if(yPlus <= 30 && yPlus > 5.0) {
7751 u[0] = uTau * (C1 * log(yPlus) + C2);
7752 } else {
7753 if(yPlus > 30) {
7754 u[0] = uTau * (C3 * log(yPlus) + C4);
7755 }
7756 }
7757 }
7758
7759 u[1] = 0.0;
7760 u[2] = 0.0;
7761
7762 actualCellLength = this->grid().cellLengthAtCell(i);
7763
7764 xPos = floor(
7765 (F1B2 * lx + (a_coordinate(i, 0) - F1B2 * (actualCellLength)) / (this->c_cellLengthAtLevel(minLevel()))) + 0.1);
7766 yPos = floor(
7767 (F1B2 * ly + (a_coordinate(i, 1) - F1B2 * (actualCellLength)) / (this->c_cellLengthAtLevel(minLevel()))) + 0.1);
7768 zPos = floor(
7769 (F1B2 * lz + (a_coordinate(i, 2) - F1B2 * (actualCellLength)) / (this->c_cellLengthAtLevel(minLevel()))) + 0.1);
7770
7771 if(xPos > lx - 1 || xPos < 0 || yPos > ly - 1 || yPos < 0 || zPos > lz - 1 || zPos < 0) {
7772 cerr << "ERROR: wrong array position!" << endl;
7773 cerr << "pos=" << xPos << ", " << yPos << ", " << zPos << endl;
7774 cerr << "coorda = (" << a_coordinate(i, 2) << ", " << a_coordinate(i, 2) << ", " << a_coordinate(i, 2) << ")"
7775 << endl;
7776 cerr << "actuallength=" << actualCellLength << ", smallestlength=" << m_smallestCellLength << endl;
7777 cerr << "minlevel=" << minLevel() << ", maxLevel=" << maxLevel() << endl;
7778 cerr << "lenght on level0=" << this->c_cellLengthAtLevel(0) << endl;
7779 TERMM(1, "Wrong array position");
7780 }
7781
7782 // add normalized real parts of fluctuations
7783 u[0] += uPhysField[zPos + lz * (yPos + ly * xPos)][0];
7784 u[1] += vPhysField[zPos + lz * (yPos + ly * xPos)][0];
7785 u[2] += wPhysField[zPos + lz * (yPos + ly * xPos)][0];
7786
7787 // // add normalized real parts of fluctuations factorized by u_mean/u_max
7788 // u[0] += uPhysField[zPos+lz*(yPos+ly*xPos)][0] * u[0]/(uTau * (C3*log(m_ReTau)+C4));
7789 // u[1] += vPhysField[zPos+lz*(yPos+ly*xPos)][0] * u[0]/(uTau * (C3*log(m_ReTau)+C4));
7790 // u[2] += wPhysField[zPos+lz*(yPos+ly*xPos)][0] * u[0]/(uTau * (C3*log(m_ReTau)+C4));
7791
7792 a_variable(i, PV->RHO) = rho;
7793 a_oldVariable(i, PV->RHO) = rho;
7794 // cells[i].m_oldVariablesT1[PV->RHO] = rho;
7795 a_variable(i, PV->U) = u[0];
7796 a_oldVariable(i, PV->U) = u[0];
7797 // cells[i].m_oldVariablesT1[PV->U] = u[0];
7798 a_variable(i, PV->V) = u[1];
7799 a_oldVariable(i, PV->V) = u[1];
7800 // cells[i].m_oldVariablesT1[PV->V] = u[1];
7801 a_variable(i, PV->W) = u[2];
7802 a_oldVariable(i, PV->W) = u[2];
7803 // cells[i].m_oldVariablesT1[PV->W] = u[2];
7804 }
7805
7806 // initialize distr. functions
7807 initEqDistFunctions();
7808
7809 // Free the FFTW memory
7810 fftw_free(uPhysField);
7811 fftw_free(vPhysField);
7812 fftw_free(wPhysField);
7813}
7814template <>
7816 TERMM(1, "Init method only available for D3Qy, yet!");
7817}
7818
7829template <MInt nDim, MInt nDist, class SysEqn>
7831 TRACE();
7832 MInt xPos, yPos, zPos;
7833 MInt lx = 0, ly = 0, lz = 0;
7834
7835 // fft-domain dimensions
7836 // this holds the size of the domain in number of cells on lowest level
7837 lx = m_arraySize[0] / FPOW2(maxLevel() - minLevel());
7838 ly = m_arraySize[1] / FPOW2(maxLevel() - minLevel());
7839 if(nDim == 3) lz = m_arraySize[2] / FPOW2(maxLevel() - minLevel());
7840
7841 fftw_complex *uPhysField, *vPhysField, *wPhysField;
7842
7843 // field of velocities from positve frequencies
7844 uPhysField = (fftw_complex*)fftw_malloc(lx * ly * lz * sizeof(fftw_complex));
7845 vPhysField = (fftw_complex*)fftw_malloc(lx * ly * lz * sizeof(fftw_complex));
7846 wPhysField = (fftw_complex*)fftw_malloc(lx * ly * lz * sizeof(fftw_complex));
7847
7848 // in multisolver mode the velocity field is created in solver 0 and broadcasted to all others
7849 ScratchSpace<MFloat> sendRecvBufferU(lx * ly * lz, AT_, "sendRecvBufferU");
7850 ScratchSpace<MFloat> sendRecvBufferV(lx * ly * lz, AT_, "sendRecvBufferV");
7851 ScratchSpace<MFloat> sendRecvBufferW(lx * ly * lz, AT_, "sendRecvBufferW");
7852
7853
7854 if(domainId() == 0) {
7855 // create velocity field
7856 maia::math::initFft(uPhysField, vPhysField, wPhysField, lx, ly, lz, m_noPeakModes, m_Ma);
7857
7858 // copy values to buffer
7859 for(MInt p = 0; p < lx; p++) {
7860 for(MInt q = 0; q < ly; q++) {
7861 for(MInt r = 0; r < lz; r++) {
7862 sendRecvBufferU[r + lz * (q + ly * p)] = uPhysField[r + lz * (q + ly * p)][0];
7863 sendRecvBufferV[r + lz * (q + ly * p)] = vPhysField[r + lz * (q + ly * p)][0];
7864 sendRecvBufferW[r + lz * (q + ly * p)] = wPhysField[r + lz * (q + ly * p)][0];
7865 }
7866 }
7867 }
7868 }
7869
7870 MPI_Bcast(&sendRecvBufferU[0], lx * ly * lz, MPI_DOUBLE, 0, mpiComm(), AT_, "sendRecvBufferU[0]");
7871 MPI_Bcast(&sendRecvBufferV[0], lx * ly * lz, MPI_DOUBLE, 0, mpiComm(), AT_, "sendRecvBufferV[0]");
7872 MPI_Bcast(&sendRecvBufferW[0], lx * ly * lz, MPI_DOUBLE, 0, mpiComm(), AT_, "sendRecvBufferW[0]");
7873
7874 if(domainId() != 0) {
7875 // copy values from buffer
7876 for(MInt p = 0; p < lx; p++) {
7877 for(MInt q = 0; q < ly; q++) {
7878 for(MInt r = 0; r < lz; r++) {
7879 uPhysField[r + lz * (q + ly * p)][0] = sendRecvBufferU[r + lz * (q + ly * p)];
7880 vPhysField[r + lz * (q + ly * p)][0] = sendRecvBufferV[r + lz * (q + ly * p)];
7881 wPhysField[r + lz * (q + ly * p)][0] = sendRecvBufferW[r + lz * (q + ly * p)];
7882 }
7883 }
7884 }
7885 }
7886
7887 MFloat actualCellLength;
7888
7889 MFloat rho, u[3] = {0.0, 0.0, 0.0}, uTau, yPlus;
7890 MFloat radius = 0.0;
7891
7892 // all cells have the same density
7893 if(m_densityFluctuations)
7894 rho = 0.0;
7895 else
7896 rho = 1.0;
7897
7898 uTau = (MFloat)m_ReTau * m_nu / m_referenceLength;
7899
7900 // tmpwidth equals pipe-radius (in cells) * cellLength on maxLevel
7901 MFloat tmpWidth = F1B2 * m_referenceLength * m_smallestCellLength;
7902
7903 cerr << " --- prescribing mean velocity profile for turbulent pipe ---" << endl;
7904 for(MInt i = 0; i < a_noCells(); i++) {
7905 initNu(i, m_nu);
7906
7907 radius = sqrt(a_coordinate(i, 0) * a_coordinate(i, 0) + a_coordinate(i, 1) * a_coordinate(i, 1));
7908
7909 yPlus = m_ReTau * (1.0 - radius / tmpWidth);
7910
7911 u[0] = 0.0;
7912 u[1] = 0.0;
7913
7914 if(yPlus <= 5.0) {
7915 u[2] = uTau * yPlus;
7916 } else {
7917 if(yPlus <= 30 && yPlus > 5.0) {
7918 u[2] = uTau * (C1 * log(yPlus) + C2);
7919 } else {
7920 if(yPlus > 30) {
7921 u[2] = uTau * (C3 * log(yPlus) + C4);
7922 }
7923 }
7924 }
7925
7926 actualCellLength = this->grid().cellLengthAtCell(i);
7927
7928 xPos = floor(
7929 (F1B2 * lx + (a_coordinate(i, 0) - F1B2 * (actualCellLength)) / (this->c_cellLengthAtLevel(minLevel()))) + 0.1);
7930 yPos = floor(
7931 (F1B2 * ly + (a_coordinate(i, 1) - F1B2 * (actualCellLength)) / (this->c_cellLengthAtLevel(minLevel()))) + 0.1);
7932
7933 // zero z at the inlet
7934 zPos = floor(((a_coordinate(i, 2) - F1B2 * (actualCellLength)) / (this->c_cellLengthAtLevel(minLevel()))) + 0.1);
7935
7936 if(xPos > lx - 1 || xPos < 0 || yPos > ly - 1 || yPos < 0 || zPos > lz - 1 || zPos < 0) {
7937 stringstream errorMessage;
7938 errorMessage << "ERROR: wrong array position!" << endl;
7939 errorMessage << "pos=" << xPos << ", " << yPos << ", " << zPos << endl;
7940 errorMessage << "coorda = (" << a_coordinate(i, 2) << ", " << a_coordinate(i, 2) << ", " << a_coordinate(i, 2)
7941 << ")" << endl;
7942 errorMessage << "actuallength=" << actualCellLength << ", smallestlength=" << m_smallestCellLength << endl;
7943 errorMessage << "minlevel=" << minLevel() << ", maxLevel=" << maxLevel() << endl;
7944 errorMessage << "length on level0=" << this->c_cellLengthAtLevel(0) << endl;
7945 TERMM(1, errorMessage.str());
7946 }
7947
7948
7949 // m_log <<"pos="<<xPos<<", "<<yPos<<", "<<zPos<<endl;
7950 // m_log <<"uvw="<<uPhysField[zPos+lz*(yPos+ly*xPos)][0]<<", "<<vPhysField[zPos+lz*(yPos+ly*xPos)][0]<<",
7951 // "<<wPhysField[zPos+lz*(yPos+ly*xPos)][0]<<endl;
7952
7953 // add normalized real parts of fluctuations factorized by u_mean/u_max
7954 u[0] += 2.0 * uPhysField[zPos + lz * (yPos + ly * xPos)][0] * u[2] / (uTau * (C3 * log(m_ReTau) + C4));
7955 u[1] += 2.0 * vPhysField[zPos + lz * (yPos + ly * xPos)][0] * u[2] / (uTau * (C3 * log(m_ReTau) + C4));
7956 u[2] += 2.0 * wPhysField[zPos + lz * (yPos + ly * xPos)][0] * u[2] / (uTau * (C3 * log(m_ReTau) + C4));
7957
7958 a_variable(i, PV->RHO) = rho;
7959 a_oldVariable(i, PV->RHO) = rho;
7960 // cells[i].m_oldVariablesT1[PV->RHO] = rho;
7961 a_variable(i, PV->U) = u[0];
7962 a_oldVariable(i, PV->U) = u[0];
7963 // cells[i].m_oldVariablesT1[PV->U] = u[0];
7964 a_variable(i, PV->V) = u[1];
7965 a_oldVariable(i, PV->V) = u[1];
7966 // cells[i].m_oldVariablesT1[PV->V] = u[1];
7967 a_variable(i, PV->W) = u[2];
7968 a_oldVariable(i, PV->W) = u[2];
7969 // cells[i].m_oldVariablesT1[PV->W] = u[2];
7970 }
7971
7972 // initialize distr. functions
7973 initEqDistFunctions();
7974
7975 // Free the FftW memory
7976 fftw_free(uPhysField);
7977 fftw_free(vPhysField);
7978 fftw_free(wPhysField);
7979}
7980template <>
7982 TERMM(1, "Init method only available for D3Qy, yet!");
7983}
7984
7996template <MInt nDim, MInt nDist, class SysEqn>
7998 TRACE();
7999 MInt xPos, yPos, zPos;
8000 MInt lx = 0, ly = 0, lz = 0;
8001
8002 MFloat actualCellLength;
8003 MFloat GaussFactor, sigma, deltaOmega0;
8004
8005 MFloat rho = 1.0, u[3] = {0.0, 0.0, 0.0};
8006
8007 // fft-domain dimensions
8008 // this holds the size of the domain in number of cells on lowest level
8009 lx = m_arraySize[0] / FPOW2(maxLevel() - minLevel());
8010 ly = m_arraySize[1] / FPOW2(maxLevel() - minLevel());
8011 if(nDim == 3) lz = m_arraySize[2] / FPOW2(maxLevel() - minLevel());
8012
8013 fftw_complex *uPhysField, *vPhysField, *wPhysField;
8014
8015 // field of velocities from positve frequencies (is deleted at the end of the method)
8016 uPhysField = (fftw_complex*)fftw_malloc(lx * ly * lz * sizeof(fftw_complex));
8017 vPhysField = (fftw_complex*)fftw_malloc(lx * ly * lz * sizeof(fftw_complex));
8018 wPhysField = (fftw_complex*)fftw_malloc(lx * ly * lz * sizeof(fftw_complex));
8019
8020 // in multisolver mode the velocity field is created in solver 0 and broadcasted to all others
8021 ScratchSpace<MFloat> sendRecvBufferU(lx * ly * lz, AT_, "sendRecvBufferU");
8022 ScratchSpace<MFloat> sendRecvBufferV(lx * ly * lz, AT_, "sendRecvBufferV");
8023 ScratchSpace<MFloat> sendRecvBufferW(lx * ly * lz, AT_, "sendRecvBufferW");
8024 if(domainId() == 0) {
8025 // create velocity field
8026 maia::math::initFft(uPhysField, vPhysField, wPhysField, lx, ly, lz, m_noPeakModes, m_Ma);
8027
8028 // copy values to buffer
8029 for(MInt p = 0; p < lx; p++) {
8030 for(MInt q = 0; q < ly; q++) {
8031 for(MInt r = 0; r < lz; r++) {
8032 sendRecvBufferU[r + lz * (q + ly * p)] = uPhysField[r + lz * (q + ly * p)][0];
8033 sendRecvBufferV[r + lz * (q + ly * p)] = vPhysField[r + lz * (q + ly * p)][0];
8034 sendRecvBufferW[r + lz * (q + ly * p)] = wPhysField[r + lz * (q + ly * p)][0];
8035 }
8036 }
8037 }
8038 }
8039
8040 MPI_Bcast(&sendRecvBufferU[0], lx * ly * lz, MPI_DOUBLE, 0, mpiComm(), AT_, "sendRecvBufferU[0]");
8041 MPI_Bcast(&sendRecvBufferV[0], lx * ly * lz, MPI_DOUBLE, 0, mpiComm(), AT_, "sendRecvBufferV[0]");
8042 MPI_Bcast(&sendRecvBufferW[0], lx * ly * lz, MPI_DOUBLE, 0, mpiComm(), AT_, "sendRecvBufferW[0]");
8043
8044 if(domainId() != 0) {
8045 // copy values from buffer
8046 for(MInt p = 0; p < lx; p++) {
8047 for(MInt q = 0; q < ly; q++) {
8048 for(MInt r = 0; r < lz; r++) {
8049 uPhysField[r + lz * (q + ly * p)][0] = sendRecvBufferU[r + lz * (q + ly * p)];
8050 vPhysField[r + lz * (q + ly * p)][0] = sendRecvBufferV[r + lz * (q + ly * p)];
8051 wPhysField[r + lz * (q + ly * p)][0] = sendRecvBufferW[r + lz * (q + ly * p)];
8052 }
8053 }
8054 }
8055 }
8056
8057
8058 ScratchSpace<MFloat> bBox(6, AT_, "bBox");
8059 MFloat* bBoxPtr = &bBox[0];
8060
8061 m_geometry->getBoundingBox(bBoxPtr);
8062
8063 // all cells have the same density
8064 if(m_densityFluctuations)
8065 rho = 0.0;
8066 else
8067 rho = 1.0;
8068
8069 // initial vorticity thickness [cells]
8070 deltaOmega0 = m_referenceLength * m_smallestCellLength;
8071
8072 // width of the Gaussian distribution for perturbation scaling
8073 // depends on initial vorticity thickness
8074 sigma = F1B2 * deltaOmega0;
8075
8076 m_log << " initial macroscopic vorticity thickness: " << deltaOmega0 << endl;
8077
8078 cerr << " --- prescribing mean velocity profile for turbulent mixing layer ---" << endl;
8079 for(MInt i = 0; i < a_noCells(); i++) {
8080 initNu(i, m_nu);
8081
8082 GaussFactor = exp(-(a_coordinate(i, 1) / sigma) * (a_coordinate(i, 1) / sigma) * F1B2);
8083
8084 u[0] = m_Ma * LBCS * tanh(2.0 * a_coordinate(i, 1) / deltaOmega0);
8085 u[1] = 0.0;
8086 u[2] = 0.0;
8087
8088 actualCellLength = this->grid().cellLengthAtCell(i);
8089
8090 xPos = floor(
8091 (F1B2 * lx + (a_coordinate(i, 0) - F1B2 * (actualCellLength)) / (this->c_cellLengthAtLevel(minLevel()))) + 0.1);
8092 yPos = floor(
8093 (F1B2 * ly + (a_coordinate(i, 1) - F1B2 * (actualCellLength)) / (this->c_cellLengthAtLevel(minLevel()))) + 0.1);
8094
8095 zPos = floor(
8096 (F1B2 * lz + (a_coordinate(i, 2) - F1B2 * (actualCellLength)) / (this->c_cellLengthAtLevel(minLevel()))) + 0.1);
8097
8098 if(xPos > lx - 1 || xPos < 0 || yPos > ly - 1 || yPos < 0 || zPos > lz - 1 || zPos < 0) {
8099 stringstream errorMessage;
8100 errorMessage << "ERROR: wrong array position!" << endl;
8101 errorMessage << "pos=" << xPos << ", " << yPos << ", " << zPos << endl;
8102 errorMessage << "coorda = (" << a_coordinate(i, 2) << ", " << a_coordinate(i, 2) << ", " << a_coordinate(i, 2)
8103 << ")" << endl;
8104 errorMessage << "actuallength=" << actualCellLength << ", smallestlength=" << m_smallestCellLength << endl;
8105 errorMessage << "minlevel=" << minLevel() << ", maxLevel=" << maxLevel() << endl;
8106 errorMessage << "lenght on level0=" << this->c_cellLengthAtLevel(0) << endl;
8107 TERMM(1, errorMessage.str());
8108 }
8109
8110 // m_log <<"pos="<<xPos<<", "<<yPos<<", "<<zPos<<endl;
8111 // m_log <<"uvw="<<uPhysField[zPos+lz*(yPos+ly*xPos)][0]<<", "<<vPhysField[zPos+lz*(yPos+ly*xPos)][0]<<",
8112 // "<<wPhysField[zPos+lz*(yPos+ly*xPos)][0]<<endl;
8113
8114 // add normalized real parts of fluctuations factorized by Gaussian
8115 u[0] += uPhysField[zPos + lz * (yPos + ly * xPos)][0] * GaussFactor;
8116 u[1] += vPhysField[zPos + lz * (yPos + ly * xPos)][0] * GaussFactor;
8117 u[2] += wPhysField[zPos + lz * (yPos + ly * xPos)][0] * GaussFactor;
8118
8119 a_variable(i, PV->RHO) = rho;
8120 a_variable(i, PV->U) = u[0];
8121 a_variable(i, PV->V) = u[1];
8122 a_variable(i, PV->W) = u[2];
8123
8124 a_oldVariable(i, PV->RHO) = rho;
8125 // cells[i].m_oldVariablesT1[PV->RHO] = rho;
8126
8127 a_oldVariable(i, PV->U) = u[0];
8128 // cells[i].m_oldVariablesT1[PV->U] = u[0];
8129
8130 a_oldVariable(i, PV->V) = u[1];
8131 // cells[i].m_oldVariablesT1[PV->V] = u[1];
8132
8133 a_oldVariable(i, PV->W) = u[2];
8134 // cells[i].m_oldVariablesT1[PV->W] = u[2];
8135 }
8136
8137 // takeCurl();
8138
8139 // initialize distr. functions
8140 initNonEqDistFunctions();
8141
8142 // Free the FFTW memory
8143 fftw_free(uPhysField);
8144 fftw_free(vPhysField);
8145 fftw_free(wPhysField);
8146}
8147template <>
8149 TERMM(1, "Init method only available for D3Qy, yet!");
8150}
8151
8164template <MInt nDim, MInt nDist, class SysEqn>
8166 TRACE();
8167
8168 MInt xPos, yPos, zPos;
8169 MInt lx = 0, ly = 0, lz = 0;
8170 MInt lxCoarse = 0, lyCoarse = 0, lzCoarse = 0;
8171
8172 MFloat actualCellLength;
8173 MFloat GaussFactor, sigma, deltaOmega0;
8174
8175 MFloat rho, u[3] = {0.0, 0.0, 0.0};
8176
8177 // all cells have the same density
8178 if(m_densityFluctuations)
8179 rho = 0.0;
8180 else
8181 rho = 1.0;
8182
8183 // fft-domain dimensions
8184 // this holds the size of the domain in number of cells on highest level
8185 lx = m_arraySize[0];
8186 ly = m_arraySize[1];
8187 if(nDim == 3) lz = m_arraySize[2];
8188
8189 // size of the filtered domain
8190 lxCoarse = lx / 2;
8191 lyCoarse = ly / 2;
8192 lzCoarse = lz / 2;
8193
8194 // field of velocities filtered to coarse grid (is deleted at the end of the method)
8195 ScratchSpace<MFloat> uPhysFieldCoarse(lxCoarse * lyCoarse * lzCoarse, AT_, "uPhysFieldCoarse");
8196 ScratchSpace<MFloat> vPhysFieldCoarse(lxCoarse * lyCoarse * lzCoarse, AT_, "vPhysFieldCoarse");
8197 ScratchSpace<MFloat> wPhysFieldCoarse(lxCoarse * lyCoarse * lzCoarse, AT_, "wPhysFieldCoarse");
8198
8199 // in multisolver mode the velocity field is created in solver 0 and broadcasted to all others
8200 ScratchSpace<MFloat> sendRecvBufferU(lxCoarse * lyCoarse * lzCoarse, AT_, "sendRecvBufferU");
8201 ScratchSpace<MFloat> sendRecvBufferV(lxCoarse * lyCoarse * lzCoarse, AT_, "sendRecvBufferV");
8202 ScratchSpace<MFloat> sendRecvBufferW(lxCoarse * lyCoarse * lzCoarse, AT_, "sendRecvBufferW");
8203
8204 if(domainId() == 0) {
8205 // create velocity field
8206 MFloat* uPhysFieldCoarsePtr = &uPhysFieldCoarse[0];
8207 MFloat* vPhysFieldCoarsePtr = &vPhysFieldCoarse[0];
8208 MFloat* wPhysFieldCoarsePtr = &wPhysFieldCoarse[0];
8209 maia::math::initFftFilter(uPhysFieldCoarsePtr, vPhysFieldCoarsePtr, wPhysFieldCoarsePtr, lx, ly, lz, lxCoarse,
8210 lyCoarse, lzCoarse, m_noPeakModes, m_Ma);
8211
8212 // copy values to buffer
8213 for(MInt p = 0; p < lxCoarse; p++) {
8214 for(MInt q = 0; q < lyCoarse; q++) {
8215 for(MInt r = 0; r < lzCoarse; r++) {
8216 sendRecvBufferU[r + lzCoarse * (q + lyCoarse * p)] = uPhysFieldCoarse[r + lzCoarse * (q + lyCoarse * p)];
8217 sendRecvBufferV[r + lzCoarse * (q + lyCoarse * p)] = vPhysFieldCoarse[r + lzCoarse * (q + lyCoarse * p)];
8218 sendRecvBufferW[r + lzCoarse * (q + lyCoarse * p)] = wPhysFieldCoarse[r + lzCoarse * (q + lyCoarse * p)];
8219 }
8220 }
8221 }
8222 }
8223
8224 MPI_Bcast(&sendRecvBufferU[0], lxCoarse * lyCoarse * lzCoarse, MPI_DOUBLE, 0, mpiComm(), AT_, "sendRecvBufferU[0]");
8225 MPI_Bcast(&sendRecvBufferV[0], lxCoarse * lyCoarse * lzCoarse, MPI_DOUBLE, 0, mpiComm(), AT_, "sendRecvBufferV[0]");
8226 MPI_Bcast(&sendRecvBufferW[0], lxCoarse * lyCoarse * lzCoarse, MPI_DOUBLE, 0, mpiComm(), AT_, "sendRecvBufferW[0]");
8227
8228 if(domainId() != 0) {
8229 // copy values from buffer
8230 for(MInt p = 0; p < lxCoarse; p++) {
8231 for(MInt q = 0; q < lyCoarse; q++) {
8232 for(MInt r = 0; r < lzCoarse; r++) {
8233 uPhysFieldCoarse[r + lzCoarse * (q + lyCoarse * p)] = sendRecvBufferU[r + lzCoarse * (q + lyCoarse * p)];
8234 vPhysFieldCoarse[r + lzCoarse * (q + lyCoarse * p)] = sendRecvBufferV[r + lzCoarse * (q + lyCoarse * p)];
8235 wPhysFieldCoarse[r + lzCoarse * (q + lyCoarse * p)] = sendRecvBufferW[r + lzCoarse * (q + lyCoarse * p)];
8236 }
8237 }
8238 }
8239 }
8240
8241 ScratchSpace<MFloat> bBox(6, AT_, "bBox");
8242 MFloat* bBoxPtr = &bBox[0];
8243 m_geometry->getBoundingBox(bBoxPtr);
8244
8245 // initial vorticity thickness [cells]
8246 deltaOmega0 = m_referenceLength * m_smallestCellLength;
8247
8248 // width of the Gaussian distribution for perturbation scaling
8249 // depends on initial vorticity thickness
8250 sigma = deltaOmega0;
8251
8252 m_log << " initial macroscopic vorticity thickness: " << deltaOmega0 << endl;
8253
8254 cerr << " --- prescribing mean velocity profile for turbulent mixing layer ---" << endl;
8255 for(MInt i = 0; i < a_noCells(); i++) {
8256 initNu(i, m_nu);
8257
8258 GaussFactor = exp(-(a_coordinate(i, 1) / sigma) * (a_coordinate(i, 1) / sigma) * F1B2);
8259
8260 u[0] = m_Ma * LBCS * tanh(2.0 * a_coordinate(i, 1) / deltaOmega0);
8261 u[1] = 0.0;
8262 u[2] = 0.0;
8263
8264 actualCellLength = this->grid().cellLengthAtCell(i);
8265
8266 xPos = floor(
8267 (F1B2 * lxCoarse + (a_coordinate(i, 0) - F1B2 * (actualCellLength)) / (this->c_cellLengthAtLevel(maxLevel())))
8268 + 0.1);
8269 yPos = floor(
8270 (F1B2 * lyCoarse + (a_coordinate(i, 1) - F1B2 * (actualCellLength)) / (this->c_cellLengthAtLevel(maxLevel())))
8271 + 0.1);
8272
8273 zPos = floor(
8274 (F1B2 * lzCoarse + (a_coordinate(i, 2) - F1B2 * (actualCellLength)) / (this->c_cellLengthAtLevel(maxLevel())))
8275 + 0.1);
8276
8277 if(xPos > lxCoarse - 1 || xPos < 0 || yPos > lyCoarse - 1 || yPos < 0 || zPos > lzCoarse - 1 || zPos < 0) {
8278 cerr << "ERROR: wrong array position!" << endl;
8279 cerr << "pos=" << xPos << ", " << yPos << ", " << zPos << endl;
8280 cerr << "coorda = (" << a_coordinate(i, 2) << ", " << a_coordinate(i, 2) << ", " << a_coordinate(i, 2) << ")"
8281 << endl;
8282 cerr << "actuallength=" << actualCellLength << ", smallestlength=" << m_smallestCellLength << endl;
8283 cerr << "minlevel=" << minLevel() << ", maxLevel=" << maxLevel() << endl;
8284 cerr << "lenght on level0=" << this->c_cellLengthAtLevel(0) << endl;
8285 TERMM(1, "Wrong array position");
8286 }
8287
8288 // m_log <<"pos="<<xPos<<", "<<yPos<<", "<<zPos<<endl;
8289 // m_log <<"uvw="<<uPhysField[zPos+lz*(yPos+ly*xPos)][0]<<", "<<vPhysField[zPos+lz*(yPos+ly*xPos)][0]<<",
8290 // "<<wPhysField[zPos+lz*(yPos+ly*xPos)][0]<<endl;
8291
8292 // add normalized real parts of fluctuations factorized by Gaussian
8293 u[0] += uPhysFieldCoarse[zPos + lzCoarse * (yPos + lyCoarse * xPos)] * GaussFactor;
8294 u[1] += vPhysFieldCoarse[zPos + lzCoarse * (yPos + lyCoarse * xPos)] * GaussFactor;
8295 u[2] += wPhysFieldCoarse[zPos + lzCoarse * (yPos + lyCoarse * xPos)] * GaussFactor;
8296
8297 a_variable(i, PV->RHO) = rho;
8298 a_variable(i, PV->U) = u[0];
8299 a_variable(i, PV->V) = u[1];
8300 a_variable(i, PV->W) = u[2];
8301
8302 a_oldVariable(i, PV->RHO) = rho;
8303 // cells[i].m_oldVariablesT1[PV->RHO] = rho;
8304
8305 a_oldVariable(i, PV->U) = u[0];
8306 // cells[i].m_oldVariablesT1[PV->U] = u[0];
8307
8308 a_oldVariable(i, PV->V) = u[1];
8309 // cells[i].m_oldVariablesT1[PV->V] = u[1];
8310
8311 a_oldVariable(i, PV->W) = u[2];
8312 // cells[i].m_oldVariablesT1[PV->W] = u[2];
8313 }
8314
8315 // takeCurl();
8316
8317 // initialize distr. functions
8318 initNonEqDistFunctions();
8319 // initEqDistFunctions();
8320}
8321template <>
8323 TERMM(1, "Init method only available for D3Qy, yet!");
8324}
8325
8340template <MInt nDim, MInt nDist, class SysEqn>
8342 TRACE();
8343 // adapted from FV:
8344 IF_CONSTEXPR(nDim == 2) TERMM(-1, "Only works for 3D!");
8345 const MFloat time0 = MPI_Wtime();
8346 const MInt fftLevel = grid().maxUniformRefinementLevel();
8347 const MFloat DX = c_cellLengthAtLevel(fftLevel);
8348 if(fftLevel > grid().maxUniformRefinementLevel()) {
8349 mTerm(1, AT_, "Isotropic mesh expected (0).");
8350 }
8351 MInt noVars = nDim + 1; // U, V, W, RHO
8352
8353 std::array<MFloat, nDim * 2> bBox;
8354 m_geometry->getBoundingBox(bBox.data());
8355
8356 /* if(Context::propertyExists("cutOffCoordinates", m_solverId)) {
8357 for(MInt i = 0; i < nDim; i++) {
8358 bBox[i] = numeric_limits<MInt>::max();
8359 bBox[nDim + i] = numeric_limits<MInt>::min();
8360 }
8361 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
8362 if(a_isHalo(cellId)) continue;
8363 //if(a_isPeriodic(cellId)) continue;
8364 if(a_isBndryGhostCell(cellId)) continue;
8365 for(MInt i = 0; i < nDim; i++) {
8366 bBox[i] = mMin(bBox[i], a_coordinate(cellId, i) - F1B2 * c_cellLengthAtCell(cellId));
8367 bBox[nDim + i] = mMax(bBox[nDim + i], a_coordinate(cellId, i) + F1B2 * c_cellLengthAtCell(cellId));
8368 }
8369 }
8370 MPI_Allreduce(MPI_IN_PLACE, &bBox[0], nDim, MPI_DOUBLE, MPI_MIN, mpiComm(), AT_, "MPI_IN_PLACE", "bBox[0]");
8371 MPI_Allreduce(MPI_IN_PLACE, &bBox[nDim], nDim, MPI_DOUBLE, MPI_MAX, mpiComm(), AT_, "MPI_IN_PLACE",
8372 "bBox[nDim]");
8373 } */
8374
8375 // fft-domain dimensions
8376 // this holds the size of the domain in number of cells on lowest level
8377
8378 const MFloat dxeps = 0.1 * DX;
8379 MInt nx = (bBox[3] - bBox[0] + dxeps) / DX;
8380 MInt ny = (bBox[4] - bBox[1] + dxeps) / DX;
8381 MInt nz = (bBox[5] - bBox[2] + dxeps) / DX;
8382 const MInt size = nx * ny * nz;
8383
8384 getReLambdaAndUrmsInit();
8385 if(domainId() == 0) cerr << "UrmsInit: " << m_UrmsInit << endl << "ReLambdaInit: " << m_ReLambda << endl;
8386
8387 // consistency check
8388 const MFloat nuCheck = m_referenceLength * m_UrmsInit / m_Re;
8389 if(abs(nuCheck - m_nu) > 0.01 * m_nu) // 1% difference is tolerated between nuCheck and nuLb
8390 mTerm(1, AT_, "nu_LB and nu_check are not consistent! Check Re, Ma and UrmsInit");
8391
8392 MFloat rhoInfinity = F1;
8393 MFloat UInfinity = m_UrmsInit; // equal to m_Ma * LBCS
8394
8395 MBool goodSpectrum = false;
8396 MUlong seed = 0;
8397
8398 MInt spectrumId = 2; // prescribed energy spectrum, see maiamath.cpp
8399 spectrumId = Context::getSolverProperty<MInt>("spectrumId", this->m_solverId, AT_, &spectrumId);
8400 MFloat kpRatio = F4; // peak wave number of prescribed spectrum
8401 kpRatio = Context::getSolverProperty<MFloat>("kpRatio", this->m_solverId, AT_, &kpRatio);
8402
8403 while(!goodSpectrum) {
8404 fftw_complex* uPhysField;
8405 fftw_complex* nabla2P = nullptr;
8406 MIntScratchSpace fftInfo(4, AT_, "fftInfo");
8407
8408 seed = maia::math::initFft(uPhysField, nabla2P, nx, ny, nz, kpRatio, spectrumId, fftInfo, mpiComm(),
8409 false); // Using method of Lennart Schneiders, not Ma-number dependent
8410
8411 if(domainId() == 0) {
8412 std::cerr << "Theoretical SPECTRUM: kinetic energy: " << 1.5 * POW2(m_UrmsInit)
8413 << ", dissipation rate * Box length / Urms,0^3: "
8414 << 72.0 * POW2(kpRatio * PI) * m_nu / (m_UrmsInit * nx) << ")"
8415 << ", integral length/unit length: " << F3B8 / kpRatio << ")" << std::endl;
8416 }
8417
8418 MInt maxRank = fftInfo[0];
8419 MInt local_n0 = fftInfo[1];
8420 MInt local_0_start = fftInfo[2];
8421 MInt alloc_local = fftInfo[3];
8422
8423 MIntScratchSpace noSendIds(globalNoDomains(), AT_, "noSendIds");
8424 MInt sendIdsSize = 0;
8425 MIntScratchSpace offsetsIds(globalNoDomains() + 1, AT_, "offsetsIds");
8426 MInt locOffsetIds = (globalDomainId() < maxRank) ? ((MInt)local_0_start) * ny * nz : size;
8427 MPI_Allgather(&locOffsetIds, 1, MPI_INT, &offsetsIds[0], 1, MPI_INT, mpiComm(), AT_, "locOffsetIds",
8428 "offsetsIds[0]");
8429 offsetsIds(globalNoDomains()) = size;
8430 noSendIds.fill(0);
8431
8432 // Count no of sendIds
8433 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
8434 if(a_isHalo(cellId)) continue;
8435 if(a_isBndryGhostCell(cellId)) continue;
8436 if(a_level(cellId) != fftLevel) continue;
8437 MFloat actualCellLength = grid().cellLengthAtLevel(a_level(cellId));
8438 MInt xPos = floor((F1B2 * nx + (a_coordinate(cellId, 0) - F1B2 * (actualCellLength)) / DX) + 0.1);
8439 MInt yPos = floor((F1B2 * ny + (a_coordinate(cellId, 1) - F1B2 * (actualCellLength)) / DX) + 0.1);
8440 MInt zPos = floor((F1B2 * nz + (a_coordinate(cellId, 2) - F1B2 * (actualCellLength)) / DX) + 0.1);
8441 MInt pos = maia::math::getGlobalPosFFTW(xPos, yPos, zPos, ny, nz);
8442 MInt nghbrDomain = mMin(maxRank - 1, pos / (size / maxRank));
8443 while(pos < offsetsIds(nghbrDomain) || pos >= offsetsIds(nghbrDomain + 1)) {
8444 if(pos < offsetsIds(nghbrDomain)) nghbrDomain--;
8445 if(pos >= offsetsIds(nghbrDomain + 1)) nghbrDomain++;
8446 }
8447 if(nghbrDomain >= maxRank) mTerm(1, AT_, "wrong domain");
8448 noSendIds(nghbrDomain)++;
8449 sendIdsSize++;
8450 }
8451 MIntScratchSpace sendIdsOffsets(globalNoDomains(), AT_, "sendIdsOffsets");
8452 MIntScratchSpace sendIdsOffsetsTmp(globalNoDomains(), AT_, "sendIdsOffsetsTmp");
8453 sendIdsOffsets[0] = 0;
8454 sendIdsOffsetsTmp[0] = 0;
8455 for(MInt nghbrDomain = 0; nghbrDomain < globalNoDomains() - 1; nghbrDomain++) {
8456 sendIdsOffsets[nghbrDomain + 1] = sendIdsOffsets[nghbrDomain] + noSendIds[nghbrDomain];
8457 sendIdsOffsetsTmp[nghbrDomain + 1] = sendIdsOffsets[nghbrDomain] + noSendIds[nghbrDomain];
8458 }
8459 MIntScratchSpace sendIds(sendIdsSize, AT_, "sendIdsSize");
8460
8461 // Fill sendIds
8462 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
8463 if(a_isHalo(cellId)) continue;
8464 if(a_isBndryGhostCell(cellId)) continue;
8465 if(a_level(cellId) != fftLevel) continue;
8466 MFloat actualCellLength = grid().cellLengthAtLevel(a_level(cellId));
8467 MInt xPos = floor((F1B2 * nx + (a_coordinate(cellId, 0) - F1B2 * (actualCellLength)) / DX) + 0.1);
8468 MInt yPos = floor((F1B2 * ny + (a_coordinate(cellId, 1) - F1B2 * (actualCellLength)) / DX) + 0.1);
8469 MInt zPos = floor((F1B2 * nz + (a_coordinate(cellId, 2) - F1B2 * (actualCellLength)) / DX) + 0.1);
8470 MInt pos = maia::math::getGlobalPosFFTW(xPos, yPos, zPos, nx, ny);
8471 MInt nghbrDomain = mMin(maxRank - 1, pos / (size / maxRank));
8472 while(pos < offsetsIds(nghbrDomain) || pos >= offsetsIds(nghbrDomain + 1)) {
8473 if(pos < offsetsIds(nghbrDomain)) nghbrDomain--;
8474 if(pos >= offsetsIds(nghbrDomain + 1)) nghbrDomain++;
8475 }
8476 if(nghbrDomain >= maxRank) mTerm(1, AT_, "wrong domain");
8477 sendIds[sendIdsOffsetsTmp[nghbrDomain]++] = pos;
8478 }
8479 MIntScratchSpace noRecvIds(globalNoDomains(), AT_, "noRecvIds");
8480 noRecvIds.fill(0);
8481 MPI_Alltoall(&noSendIds[0], 1, MPI_INT, &noRecvIds[0], 1, MPI_INT, mpiComm(), AT_, "noSendIds[0]", "noRecvIds[0]");
8482
8483 MIntScratchSpace recvIdsOffsets(globalNoDomains(), AT_, "recvIdsOffsets");
8484 recvIdsOffsets[0] = 0;
8485 MInt recvIdsSize = 0;
8486 for(MInt nghbrDomain = 0; nghbrDomain < globalNoDomains() - 1; nghbrDomain++) {
8487 recvIdsOffsets[nghbrDomain + 1] = recvIdsOffsets[nghbrDomain] + noRecvIds[nghbrDomain];
8488 recvIdsSize += noRecvIds[nghbrDomain];
8489 }
8490 recvIdsSize += noRecvIds[globalNoDomains() - 1];
8491
8492 // Exchange Ids
8493 MIntScratchSpace recvIds(mMax(1, recvIdsSize), AT_, "recvIds");
8494 MPI_Alltoallv(&sendIds[0], &noSendIds[0], &sendIdsOffsets[0], MPI_INT, &recvIds[0], &noRecvIds[0],
8495 &recvIdsOffsets[0], MPI_INT, mpiComm(), AT_, "sendIds[0]", "recvIds[0]");
8496
8497 MIntScratchSpace sendVarsOffsets(globalNoDomains(), AT_, "sendVarsOffsets");
8498 MIntScratchSpace sendVarsOffsetsTmp(globalNoDomains(), AT_, "sendVarsOffsetsTmp");
8499 MIntScratchSpace noSendVars(globalNoDomains(), AT_, "noSendVars");
8500 sendVarsOffsets[0] = 0;
8501 sendVarsOffsetsTmp[0] = 0;
8502 MInt sendVarsSize = 0;
8503 for(MInt i = 0; i < globalNoDomains() - 1; i++) {
8504 sendVarsOffsets[i + 1] = sendVarsOffsets[i] + noRecvIds[i] * 3;
8505 sendVarsOffsetsTmp[i + 1] = sendVarsOffsetsTmp[i] + noRecvIds[i] * 3;
8506 noSendVars[i] = noRecvIds[i] * 3;
8507 sendVarsSize += noRecvIds[i] * 3;
8508 }
8509 if(recvIdsSize != 0) {
8510 noSendVars[globalNoDomains() - 1] = noRecvIds[globalNoDomains() - 1] * 3;
8511 sendVarsSize += noRecvIds[globalNoDomains() - 1] * 3;
8512 }
8513
8514 // Fill sendVars: for each Id received 3 variables have to be send
8515 MFloatScratchSpace sendVars(mMax(1, sendVarsSize), AT_, "sendVars");
8516 sendVars.fill(0);
8517 MFloat cnt = F0;
8518 MFloat upr[3] = {F0, F0, F0};
8519 for(MInt i = 0; i < recvIdsSize; i++) {
8520 MInt pos = recvIds[i];
8521 ASSERT(pos > -1 && pos < size, "");
8522 if(!(pos >= ((MInt)local_0_start) * nx * ny && pos < ((MInt)(local_0_start + local_n0) * ny * nx))) {
8523 mTerm(1, AT_, "Position not available on this domain(1).");
8524 }
8525 MInt localPos = pos - (((MInt)local_0_start) * ny * nz);
8526 if(3 * localPos + 2 > alloc_local) {
8527 mTerm(1, AT_, "index exceeds array(1)");
8528 }
8529 sendVars[i * 3] = uPhysField[3 * localPos][0];
8530 sendVars[i * 3 + 1] = uPhysField[3 * localPos + 1][0];
8531 sendVars[i * 3 + 2] = uPhysField[3 * localPos + 2][0];
8532
8533 MFloat u = uPhysField[3 * localPos][0];
8534 MFloat v = uPhysField[3 * localPos + 1][0];
8535 MFloat w = uPhysField[3 * localPos + 2][0];
8536 upr[0] += POW2(u);
8537 upr[1] += POW2(v);
8538 upr[2] += POW2(w);
8539 cnt++;
8540 }
8541
8542 MPI_Allreduce(MPI_IN_PLACE, &cnt, 1, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "cnt");
8543 MPI_Allreduce(MPI_IN_PLACE, &upr, 3, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "upr");
8544
8545 MFloat uprime0 = sqrt(F1B3 * (upr[0] + upr[1] + upr[2]) / cnt);
8546
8547 fftw_free(uPhysField);
8548
8549 MIntScratchSpace recvVarsOffsets(globalNoDomains(), AT_, "recvVarsOffsets");
8550 MIntScratchSpace noRecvVars(globalNoDomains(), AT_, "noRecvVars");
8551 recvVarsOffsets[0] = 0;
8552 MInt recvVarsSize = 0;
8553 for(MInt i = 0; i < globalNoDomains() - 1; i++) {
8554 recvVarsOffsets[i + 1] = recvVarsOffsets[i] + noSendIds[i] * 3;
8555 noRecvVars[i] = noSendIds[i] * 3;
8556 recvVarsSize += noSendIds[i] * 3;
8557 }
8558 recvVarsSize += noSendIds[globalNoDomains() - 1] * 3;
8559 noRecvVars[globalNoDomains() - 1] = noSendIds[globalNoDomains() - 1] * 3;
8560
8561 // Exchange Variables
8562 MFloatScratchSpace recvVars(recvVarsSize, AT_, "recvVars");
8563 recvVars.fill(0);
8564 MPI_Alltoallv(&sendVars[0], &noSendVars[0], &sendVarsOffsets[0], MPI_DOUBLE, &recvVars[0], &noRecvVars[0],
8565 &recvVarsOffsets[0], MPI_DOUBLE, mpiComm(), AT_, "sendVars[0]", "recvVars[0]");
8566
8567 cnt = F0;
8568 upr[0] = 0;
8569 upr[1] = 0;
8570 upr[2] = 0;
8571 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
8572 if(a_isHalo(cellId)) continue;
8573 if(a_isBndryGhostCell(cellId)) continue;
8574 if(a_level(cellId) != fftLevel) continue;
8575 MFloat actualCellLength = grid().cellLengthAtLevel(a_level(cellId));
8576 MInt xPos = floor((F1B2 * nx + (a_coordinate(cellId, 0) - F1B2 * (actualCellLength)) / DX) + 0.1);
8577 MInt yPos = floor((F1B2 * ny + (a_coordinate(cellId, 1) - F1B2 * (actualCellLength)) / DX) + 0.1);
8578 MInt zPos = floor((F1B2 * nz + (a_coordinate(cellId, 2) - F1B2 * (actualCellLength)) / DX) + 0.1);
8579 MInt pos = maia::math::getGlobalPosFFTW(xPos, yPos, zPos, nx, ny);
8580 MInt nghbrDomain = mMin(maxRank - 1, pos / (size / maxRank));
8581 while(pos < offsetsIds(nghbrDomain) || pos >= offsetsIds(nghbrDomain + 1)) {
8582 if(pos < offsetsIds(nghbrDomain)) nghbrDomain--;
8583 if(pos >= offsetsIds(nghbrDomain + 1)) nghbrDomain++;
8584 }
8585 if(nghbrDomain >= maxRank) mTerm(1, AT_, "wrong domain");
8586 if(sendIds[sendIdsOffsets[nghbrDomain]] != pos) mTerm(1, AT_, "pos mismatch");
8587 MFloat u = recvVars[sendIdsOffsets[nghbrDomain] * 3];
8588 MFloat v = recvVars[sendIdsOffsets[nghbrDomain] * 3 + 1];
8589 MFloat w = recvVars[sendIdsOffsets[nghbrDomain] * 3 + 2];
8590
8591 sendIdsOffsets[nghbrDomain]++;
8592 upr[0] += POW2(u);
8593 upr[1] += POW2(v);
8594 upr[2] += POW2(w);
8595 a_variable(cellId, PV->U) = u;
8596 a_variable(cellId, PV->V) = v;
8597 a_variable(cellId, PV->W) = w;
8598 a_variable(cellId, PV->RHO) = rhoInfinity; // is going to be iterated
8599 cnt++;
8600 }
8601
8602
8603 MPI_Allreduce(MPI_IN_PLACE, &cnt, 1, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "cnt");
8604 MPI_Allreduce(MPI_IN_PLACE, &upr, 3, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "upr");
8605
8606 MFloat uprime1 = sqrt(F1B3 * (upr[0] + upr[1] + upr[2]) / cnt);
8607 upr[0] = sqrt(upr[0] / cnt);
8608 upr[1] = sqrt(upr[1] / cnt);
8609 upr[2] = sqrt(upr[2] / cnt);
8610
8611 if(fabs(uprime0 - uprime1) > exp(-10)) mTerm(1, AT_, "Communication went wrong.");
8612
8613 if(domainId() == 0)
8614 cerr << "initial urpime: " << upr[0] << " " << upr[1] << " " << upr[2] << " (" << uprime1 << ")" << endl;
8615
8616 // for LES: The initial spectrum is cut off for coarse LES grids which
8617 // results into a lower energy level. If uprime != 1, this energy
8618 // will be modified such that all resolved scales have the DNS-energy,
8619 // i.e. large scales get the energy which have been cut off at the small
8620 // scales.
8621
8622 // uprime1 = F1;
8623
8624 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
8625 if(a_isHalo(cellId)) continue;
8626 if(a_isBndryGhostCell(cellId)) continue;
8627 if(a_level(cellId) != fftLevel) continue;
8628 // scale velocities such that mean urms is UInfinity, scaling with velocity magnitude of UrmsInit
8629 MFloat u = a_variable(cellId, PV->U) * UInfinity / uprime1;
8630 MFloat v = a_variable(cellId, PV->V) * UInfinity / uprime1;
8631 MFloat w = a_variable(cellId, PV->W) * UInfinity / uprime1;
8632
8633 a_variable(cellId, PV->U) = u;
8634 a_variable(cellId, PV->V) = v;
8635 a_variable(cellId, PV->W) = w;
8636 }
8637
8638 exchangeData(&a_variable(0, 0), noVars);
8639
8640 MFloat umean[3] = {F0, F0, F0};
8641 MFloat urms[6] = {F0, F0, F0, F0, F0, F0};
8642 MFloat reyn[6] = {F0, F0, F0, F0, F0, F0};
8643 MFloat aniso[6] = {F0, F0, F0, F0, F0, F0};
8644 MFloat dudx[3] = {F0, F0, F0};
8645 MFloat skew[4] = {F0, F0, F0, F0};
8646 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
8647 if(a_isHalo(cellId)) continue;
8648 if(a_isBndryGhostCell(cellId)) continue;
8649 if(a_level(cellId) != fftLevel) continue;
8650 MFloat u = a_variable(cellId, PV->U);
8651 MFloat v = a_variable(cellId, PV->V);
8652 MFloat w = a_variable(cellId, PV->W);
8653 for(MInt i = 0; i < nDim; i++) {
8654 MInt n0 = (a_hasNeighbor(cellId, 2 * i) > 0) ? c_neighborId(cellId, 2 * i) : cellId;
8655 MInt n1 = (a_hasNeighbor(cellId, 2 * i + 1) > 0) ? c_neighborId(cellId, 2 * i + 1) : cellId;
8656 if(n0 == n1) continue;
8657 dudx[i] += POW2((a_variable(n1, PV->VV[i]) - a_variable(n0, PV->VV[i]))
8658 / ((a_coordinate(n1, i) - a_coordinate(n0, i)) / DX));
8659 skew[i] += POW3((a_variable(n1, PV->VV[i]) - a_variable(n0, PV->VV[i]))
8660 / ((a_coordinate(n1, i) - a_coordinate(n0, i)) / DX));
8661 }
8662 urms[0] += POW2(u);
8663 urms[1] += POW2(v);
8664 urms[2] += POW2(w);
8665 urms[3] += u * v;
8666 urms[4] += u * w;
8667 urms[5] += v * w;
8668 umean[0] += u;
8669 umean[1] += v;
8670 umean[2] += w;
8671 }
8672 MPI_Allreduce(MPI_IN_PLACE, &urms[0], 6, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "urms[0]");
8673 MPI_Allreduce(MPI_IN_PLACE, &umean[0], 3, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "umean[0]");
8674 MPI_Allreduce(MPI_IN_PLACE, &dudx[0], 3, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "dudx[0]");
8675 MPI_Allreduce(MPI_IN_PLACE, &skew[0], 3, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "skew[0]");
8676 skew[3] = ((skew[0] + skew[1] + skew[2]) / (F3 * cnt)) / pow((dudx[0] + dudx[1] + dudx[2]) / (F3 * cnt), 1.5);
8677 for(MInt i = 0; i < 3; i++)
8678 skew[i] = (skew[i] / cnt) / pow(dudx[i] / cnt, 1.5);
8679 for(MInt i = 0; i < 6; i++)
8680 reyn[i] = urms[i] / cnt;
8681 for(MInt i = 0; i < 6; i++)
8682 aniso[i] = urms[i] / (urms[0] + urms[1] + urms[2]);
8683 for(MInt i = 0; i < 3; i++)
8684 aniso[i] -= F1B3;
8685 for(MInt i = 0; i < 6; i++)
8686 urms[i] = sqrt(fabs(urms[i]) / cnt);
8687 for(MInt i = 0; i < 3; i++)
8688 umean[i] /= cnt;
8689 for(MInt i = 0; i < 3; i++)
8690 dudx[i] /= cnt;
8691 MFloat lambda[3];
8692 MFloat Rel[4];
8693 MFloat eps[3];
8694 for(MInt i = 0; i < 3; i++)
8695 lambda[i] = urms[i] / sqrt(dudx[i]); // Eq. 6.56 Turbulent Flows Pope two-point correlation
8696
8697 if(domainId() == 0)
8698 cerr << "u_mean: " << umean[0] << " " << umean[1] << " " << umean[2] << " (" << (MInt)cnt << ")" << endl;
8699 if(domainId() == 0)
8700 cerr << "u_rms/u_inf: " << urms[0] / UInfinity << " " << urms[1] / UInfinity << " " << urms[2] / UInfinity << " "
8701 << urms[3] / UInfinity << " " << urms[4] / UInfinity << " " << urms[5] / UInfinity << " ("
8702 << F1B3 * (urms[0] + urms[1] + urms[2]) / UInfinity << ")" << endl;
8703 if(domainId() == 0)
8704 cerr << "skewness: " << skew[0] << " " << skew[1] << " " << skew[2] << " (" << skew[3] << ")" << endl;
8705 if(domainId() == 0)
8706 cerr << "Anisotropy: " << aniso[0] << " " << aniso[1] << " " << aniso[2] << " " << aniso[3] << " " << aniso[4]
8707 << " " << aniso[5] << endl;
8708 if(domainId() == 0)
8709 cerr << "Reynolds stress: " << reyn[0] << " " << reyn[1] << " " << reyn[2] << " " << reyn[3] << " " << reyn[4]
8710 << " " << reyn[5] << endl;
8711 if(domainId() == 0)
8712 cerr << "Realizability 1: " << reyn[3] * reyn[3] << " <= " << reyn[0] * reyn[1] << ", " << reyn[4] * reyn[4]
8713 << " <= " << reyn[0] * reyn[2] << ", " << reyn[5] * reyn[5] << " <= " << reyn[1] * reyn[2] << endl;
8714 if(domainId() == 0)
8715 cerr << "Realizability 2: det = "
8716 << reyn[0] * reyn[1] * reyn[2] + F2 * reyn[3] * reyn[4] * reyn[5] - reyn[0] * reyn[5] * reyn[5]
8717 - reyn[1] * reyn[4] * reyn[4] - reyn[2] * reyn[4] * reyn[4]
8718 << " >= 0" << endl;
8719
8720 // prescribe Taylor microscale Reynolds number
8721 // for LES: ReLambda is unkown in LES and has to be defined to get the
8722 // same viscosity as in the DNS.
8723 const MFloat time1 = MPI_Wtime();
8724 m_log << "initFFT time " << time1 - time0 << endl;
8725
8726 /*if(nx < 64) { // nx < 256 -> for LES, DNS requires refinement level of 8 or higher?
8727 ! \page propertyPage1
8728 \section ReLambdaOverwrite
8729 <code>MInt FvCartesianSolverXD::m_Re</code>\n
8730 default = <code>none</code>\n \n
8731 Overwrite Reynolds number for FV isotropic turbulence spectrum initial condition (case
8732 16). \n \n
8733 Possible values are:
8734 <ul>
8735 <li>Any positive floating point value</li>
8736 </ul>
8737 Keywords: <i>FINITE_VOLUME, INITIAL_CONDITION, ISOTROPIC, TURBULENCE</i>
8738
8739 if(!Context::propertyExists("ReLambdaOverwrite", this->m_solverId)) {
8740 mTerm(1, AT_, "Undefined ReLambda for LES grid.");
8741 }
8742 m_Re = Context::getSolverProperty<MFloat>("ReLambdaOverwrite", this->m_solverId, AT_) / m_referenceLength;
8743 Re0 = m_Re * m_nu * rhoInfinity / (rhoInfinity * UInfinity);
8744 m_log << "Overwritten Reynolds number: " << setprecision(15) << m_Re
8745 << " (Re_L=" << m_Re * (bBox[3] - bBox[0]) << ")"
8746 << " " << Re0 << endl;
8747 break;
8748 }*/
8749
8750 for(MInt i = 0; i < 3; i++)
8751 Rel[i] = urms[i] * lambda[i] / m_nu;
8752 Rel[3] = F1B3 * (urms[0] + urms[1] + urms[2]) * F1B3 * (lambda[0] + lambda[1] + lambda[2]) / m_nu;
8753
8754 if(domainId() == 0) {
8755 cerr << "Re_lambda: " << Rel[0] << " " << Rel[1] << " " << Rel[2] << " (" << Rel[3] << ", "
8756 << F1B3 * (Rel[0] + Rel[1] + Rel[2]) << ")" << endl;
8757
8758 const MFloat lambdaAvg = F1B3 * (lambda[0] + lambda[1] + lambda[2]);
8759 cerr << "lambda: " << lambda[0] << " " << lambda[1] << " " << lambda[2] << " (" << lambdaAvg << ") "
8760 << "lambda / Lb: " << lambdaAvg / m_referenceLength << endl;
8761 }
8762
8763 MFloat eps2[3];
8764 for(MInt i = 0; i < 3; i++) {
8765 eps[i] = (15.0 * m_nu * dudx[i]) * m_referenceLength / POW3(urms[i]);
8766 eps2[i] = 15.0 * m_nu * POW2(urms[i] / lambda[i]); // Eq. 6.58 Turbulent Flows Pope two-point correlation
8767 }
8768
8769 if(domainId() == 0) {
8770 cerr << "eps: " << eps[0] << " " << eps[1] << " " << eps[2] << " (" << F1B3 * (eps[0] + eps[1] + eps[2]) << ")"
8771 << endl;
8772
8773 const MFloat eps2Avg = F1B3 * (eps2[0] + eps2[1] + eps2[2]);
8774 cerr << "eps2: " << eps2[0] << " " << eps2[1] << " " << eps2[2] << " (" << eps2Avg << ")"
8775 << " eps2 * Box length / Urms,0^3: " << eps2Avg * m_referenceLength / POW3(m_UrmsInit) << endl;
8776
8777 const MFloat eta =
8778 pow(m_nu, 0.75)
8779 / pow(F1B3 * (eps2[0] + eps2[1] + eps2[2]), 0.25); // Eq. 6.1 Turbulent Flows Pope two-point correlation
8780 cerr << "Kolmogorov length: " << eta << " Kolmogorov length / Lb: " << eta / m_referenceLength << endl;
8781 }
8782 MFloat maxd = mMax(fabs(Rel[0] - Rel[1]), mMax(fabs(Rel[0] - Rel[2]), fabs(Rel[1] - Rel[2])));
8783 if(maxd < F1) m_log << "spectrum " << maxd << " " << F1B3 * (Rel[0] + Rel[1] + Rel[2]) << " " << seed << endl;
8784 // if ( maxd < 0.3 && F1B3*(Rel[0]+Rel[1]+Rel[2]) > 79.1 ) {
8785 // if ( maxd < 0.3 ) {
8786 goodSpectrum = true;
8787 if(domainId() == 0) m_log << "spectrum " << seed << endl;
8788 //}
8789 //}
8790 }
8791 if(domainId() == 0) cerr << "seed " << seed << endl;
8792 MPI_Barrier(mpiComm(), AT_);
8793
8794 // TODO: grid().maxUniformRefinementLevel() has to be replaced with maxRefinementLevel() for adaptive meshes with
8795 // local ref
8796 if(fftLevel < grid().maxUniformRefinementLevel()) {
8797 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
8798 if(a_isHalo(cellId)) continue;
8799 if(a_isBndryGhostCell(cellId)) continue;
8800 if(a_level(cellId) <= fftLevel) continue;
8801 if(c_noChildren(cellId) > 0) continue;
8802 MInt parentId = c_parentId(cellId);
8803 while(a_level(parentId) != fftLevel) {
8804 parentId = c_parentId(parentId);
8805 }
8806 if(a_level(parentId) == fftLevel) {
8807 for(MInt varId = 0; varId < noVars; varId++) {
8808 a_variable(cellId, varId) = a_variable(parentId, varId);
8809 std::cout << "a_variable(" << cellId << "," << varId << "): " << a_variable(parentId, varId) << std::endl;
8810 }
8811 }
8812 }
8813 }
8814 exchangeData(&a_variable(0, 0), noVars);
8815
8816 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
8817 for(MInt varId = 0; varId < noVars; varId++) {
8818 a_oldVariable(cellId, varId) = a_variable(cellId, varId);
8819 }
8820 }
8821
8822 // initialize distr. functions
8823 initEqDistFunctions();
8824
8825 m_log << "**************************" << endl;
8826 m_log << "Initial Condition summary" << endl;
8827 m_log << "**************************" << endl;
8828 m_log << "Re = " << m_Re << endl;
8829 m_log << "Ma = " << m_Ma << endl;
8830 m_log << "UInfinity = " << UInfinity << endl;
8831 m_log << "rhoInfinity = " << rhoInfinity << endl;
8832
8833 // check initial condition
8834 for(MInt cellId = 0; cellId < noInternalCells(); cellId++) {
8835 for(MInt v = 0; v < PV->noVariables; v++) {
8836 if(std::isnan(a_variable(cellId, v))) {
8837 cerr << "Variable " << v << " cellId : " << cellId << endl;
8838 mTerm(1, AT_, "Invalid initialcondition formulation!");
8839 }
8840 }
8841 }
8842
8843 // compute initial values for spectrum
8844 computeFFTStatistics();
8845}
8846template <>
8847void LbSolverDxQy<2, 9, maia::lb::LbSysEqnIncompressible<2, 9>>::initLatticeBgkFftIsotropicTurbulence() {
8848 mTerm(1, AT_, "Init method only available for D3Qy, yet!");
8849}
8850
8851#ifdef WAR_NVHPC_PSTL
8852template <MInt nDim, MInt nDist, class SysEqn>
8854 TRACE();
8855
8856 m_faculty.fill(-1);
8857 m_nFld.fill(-1);
8858 m_pFld.fill(-1);
8859 m_mFld1.fill(-1);
8860 m_mFld2.fill(-1);
8861 m_oppositeDist.fill(-1);
8862
8863 for(MInt i = 0; i < 50; i++) {
8864 m_faculty[i] = faculty[i];
8865 }
8866
8867 MInt fldlen = Ld::dxQyFld();
8868 for(MInt i = 0; i < fldlen; i++) {
8869 for(MInt d = 0; d < nDim; d++) {
8870 m_nFld[d * fldlen + i] = Ld::nFld(d, i);
8871 m_pFld[d * fldlen + i] = Ld::pFld(d, i);
8872 }
8873 }
8874
8875 for(MInt i = 0; i < POWX(3, nDim); i++) {
8876 for(MInt j = 0; j < POWX(3, nDim); j++) {
8877 m_idFld[i][j] = Ld::idFld(i, j);
8878 }
8879 }
8880
8881 for(MInt i = 0; i < 24; i++) {
8882 m_mFld1[i] = Ld::mFld1(i);
8883 m_mFld2[i] = Ld::mFld2(i);
8884 }
8885
8886 for(MInt i = 0; i < nDist; i++) {
8887 m_oppositeDist[i] = Ld::oppositeDist(i);
8888 }
8889
8890 for(MInt i = 0; i < 4; i++) {
8891 m_tp[i] = Ld::tp(i);
8892 }
8893
8894 for(MInt i = 0; i < 3; i++) {
8895 m_distFld[i] = Ld::distFld(i);
8896 }
8897
8898 for(MInt i = 0; i < nDist; i++) {
8899 for(MInt j = 0; j < nDim; j++) {
8900 m_ppdfDir[i * nDim + j] = Ld::ppdfDir(i, j);
8901 }
8902 }
8903
8904 for(MInt i = 0; i < nDist; i++) {
8905 m_distType[i] = Ld::distType(i);
8906 }
8907}
8908#endif
static MBool propertyExists(const MString &name, MInt solver=m_noSolvers)
This function checks if a property exists in general.
Definition: context.cpp:494
void open(const MString &filename, const MString &projectName, MInt fileType=0, MPI_Comm mpiComm=MPI_COMM_WORLD, MBool rootOnlyHardwired=false)
Opens a file by passing the parameters to InfoOut_<xyz>FileBuffer::open(...).
Definition: infoout.cpp:975
Interface class holding all relevant data and methods for treating prolongation, restriction and init...
This class represents all LB models.
Definition: lbsolverdxqy.h:29
void updateViscosity() override
Update viscosity (a_nu and a_oldNu)
void sensorInterface(std::vector< std::vector< MFloat > > &sensors, std::vector< std::bitset< 64 > > &sensorCellFlag, std::vector< MFloat > &sensorWeight, MInt sensorOffset, MInt sen) override
Simple boundary sensor for ensuring boundary refinement during adaptation.
void postPropagationSrcTerm() override
Calls the post collision routine of the source term controller.
void sensorDivergence(std::vector< std::vector< MFloat > > &sensors, std::vector< std::bitset< 64 > > &sensorCellFlag, std::vector< MFloat > &sensorWeight, MInt sensorOffset, MInt sen) override
virtual void bgkc_transport_collision_step()
Collision step for Transport Lattice-Boltzmann.
void sensorTotalPressure(std::vector< std::vector< MFloat > > &sensors, std::vector< std::bitset< 64 > > &sensorCellFlag, std::vector< MFloat > &sensorWeight, MInt sensorOffset, MInt sen) override
void initLatticeBgkGaussDiffusion()
virtual void averageGlobalVelocity(const MInt dir)
calculate average velocity of velocity component dir
LbSolverDxQy(MInt id, MInt noDistributions, GridProxy &gridProxy_, Geometry< nDim > &geometry_, const MPI_Comm comm)
void calculateSGSTensors()
Calculate tensors for dynamic Smagorinsky constant.
void bgki_euler_collision_step() override
void bgki_thermal_collision_step_base()
virtual void propagation_step_transport() override
Propagation step for Transport Lattice-Boltzmann.
void initNonEqDistFunctions()
void bgki_thermal_and_transport_collision_step_base()
Collision step for coupled Thermal Transport Lattice-Boltzmann.
typename LbSolver< nDim >::GridProxy GridProxy
Definition: lbsolverdxqy.h:34
void initSrcTerms() override
Initialize the source term controller.
void initRunCorrection() override
virtual void propagation_step_thermaltransport() override
Propagation step for coupled Thermal Transport Lattice-Boltzmann.
void initArraysForPSTL()
virtual void propagation_step_thermal() override
virtual void restartInitLb()
void bgkc_collision_step() override
virtual void refineCellLb(const MInt parentId, const MInt *childIds)
: Initialize child variables from parent
void clb_collision_step_base()
void rbgk_collision_step_base()
virtual void bgki_innerEnergy_collision_step()
virtual void initLatticeBgkTurbulentDuct()
void bgki_smagorinsky_collision_step() override
void calculateDissipation()
Calculate total energy, dissipation, and subgrid dissipation for Smagorinsky.
void initLatticeBgkFftMixingFilter()
virtual void bgki_thermal_collision_step()
void rbgk_dynamic_smago_collision_step() override
void bgki_dynamic_smago_collision_step() override
void initLatticeBgkFftChannel()
void initLatticeBgkLaminarCylinder()
virtual void propagation_step_thermal_vol() override
Propagation step for Thermal Lattice-Boltzmann.
void cumulant_collision_step() override
virtual void initLatticeBgkTurbulentMixing()
void bgki_smago_wall_collision_step() override
virtual void bgkc_totalenergy_transport_collision_step()
Collision step for coupled Thermal Transport Lattice-Boltzmann.
void initPressureForce() override
void bgki_init_collision_step() override
Consistent initialization step of the LBGK algorithm.
void bgki_smagorinsky_collision_step_base()
void updateMacroscopicVariables()
Update macroscopic variables according to incoming PPDF.
virtual void initLatticeBgkLaminar()
virtual void propagation_step_thermaltransport_vol() override
Propagation step for coupled Thermal Transport Lattice-Boltzmann.
void mrt_smagorinsky_collision_step() override
void bgki_smagorinsky_collision_step2() override
virtual void initLatticeBgkTurbulentPipe()
virtual void propagation_step() override
standard OpenMP propagation step
void rbgk_smagorinsky_collision_step() override
virtual void initTransportEqDistFunctions()
Calculates equilibrium distribution functions after initialization of macroscopic variables.
void clb_collision_step() override
void mrt_collision_step() override
virtual void propagation_step_vol() override
This function propagates the locally calculated PPDFs to the neighboring cells after the collision st...
void mrt_collision_step_base()
Collision step for the MRT-Algorithm.
void mrt2_collision_step() override
void initLatticeBgkFftPipe()
virtual void initThermalEqDistFunctions()
Calculates equilibrium distribution functions after initialization of macroscopic variables.
LbInterfaceDxQy< nDim, nDist, SysEqn > * m_interface
Definition: lbsolverdxqy.h:334
virtual void bgki_totalEnergy_collision_step()
void initLatticeBgkFftMixing()
void initLatticeBgkFftIsotropicTurbulence()
void postPropagationBc() override
LbBndCndDxQy< nDim, nDist, SysEqn > LbBndCnd
Definition: lbsolverdxqy.h:35
void initRunCorrection_()
Iterative initialize routine to obtained a valid density and non-eq field.
void sensorVorticity(std::vector< std::vector< MFloat > > &sensors, std::vector< std::bitset< 64 > > &sensorCellFlag, std::vector< MFloat > &sensorWeight, MInt sensorOffset, MInt sen) override
LbBndCnd * m_bndCnd
Pointers for the Boundary Conditions, for flow solving.
Definition: lbsolverdxqy.h:332
void rbgk_collision_step() override
void initEqDistFunctions()
Calculates equilibrium distribution functions after initialization of macroscopic variables.
virtual void restartBndCnd()
Restart bndCnd object.
virtual void updateVariablesFromOldDist_preCollision() override
virtual void initLatticeBgkTGV()
void preCollisionSrcTerm() override
Calls the pre collision routine of the source term controller.
void postCollisionBc() override
void clb_smagorinsky_collision_step() override
virtual void initLatticeBgkLaminarDir(MInt dir)
Initializes standard Lattice BGK laminar with or without a direction.
void initLatticeBgkGaussAdvection()
virtual MBool maxResidual()
virtual void initLatticeBgkVortex()
void initLatticeBgkGaussPulse()
void initLatticeBgkSpinningVorticies()
virtual void initializeLatticeBgk()
Initializes standard Lattice BGK.
virtual void initLatticeBgkTurbulentBoundary()
virtual void initLatticeBgkLaminarChannel()
virtual void controlVelocity()
control velocity of a periodic channel flow via volume forces
void sensorMeanStress(std::vector< std::vector< MFloat > > &sensors, std::vector< std::bitset< 64 > > &sensorCellFlag, std::vector< MFloat > &sensorWeight, MInt sensorOffset, MInt sen) override
virtual void initLatticeBgkLaminarPipe()
virtual void calcNodalLsValues()
virtual void removeChildsLb(const MInt parentId)
: Initialize parent variables from children
void updateVariablesFromOldDist_()
virtual void initLatticeBgkTurbulentChannel()
void averageSGSTensors(const MInt direction, MInt &count, std::vector< MFloat > &meanTensors)
Calculate average SGS tensor.
void bgki_collision_step_Guo_forcing() override
void initSrcTermController() override
Initialize the source term controller.
virtual void calculateResidual()
Calculates residuals and prints to file.
void postCollisionSrcTerm() override
Calls the post collision routine of the source term controller.
virtual void bgkc_thermal_transport_collision_step()
Collision step for coupled Thermal Transport Lattice-Boltzmann.
virtual void bgki_collision_step()
virtual void volumeForces()
apply volumeForces to the oldDistributions
virtual void bgkc_innerenergy_transport_collision_step()
Collision step for coupled Thermal Transport Lattice-Boltzmann.
virtual void updateVariablesFromOldDist() override
virtual void propagation_step_transport_vol() override
Propagation step for Transport Lattice-Boltzmann.
void initVolumeForces() override
This class is a ScratchSpace.
Definition: scratch.h:758
pointer data()
Definition: scratch.h:289
void fill(T val)
fill the scratch with a given value
Definition: scratch.h:311
MInt string2enum(MString theString)
This global function translates strings in their corresponding enum values (integer values)....
Definition: enums.cpp:20
@ LB_TURBULENT_MIXING_FILTER_INIT
Definition: enums.h:233
@ LB_LAMINAR_CYLINDER_INIT
Definition: enums.h:246
@ LB_GAUSS_PULSE_INIT
Definition: enums.h:250
@ LB_GAUSS_DIFFUSION_INIT
Definition: enums.h:251
@ LB_TURBULENT_BOUNDARY
Definition: enums.h:235
@ LB_TURBULENCE_ISOTROPIC_INIT
Definition: enums.h:234
@ LB_TURBULENT_CHANNEL_INIT
Definition: enums.h:231
@ LB_TURBULENT_PIPE_INIT
Definition: enums.h:236
@ LB_GAUSS_ADVECTION_INIT
Definition: enums.h:252
@ LB_LAMINAR_INIT_MX
Definition: enums.h:240
@ LB_LAMINAR_PIPE_INIT
Definition: enums.h:247
@ LB_FROM_ZERO_INIT
Definition: enums.h:238
@ LB_TURBULENT_DUCT_INIT
Definition: enums.h:237
@ LB_SPINNING_VORTICIES_INIT
Definition: enums.h:253
@ LB_CONVECTING_VORTEX_INIT
Definition: enums.h:255
@ LB_LAMINAR_INIT_PZ
Definition: enums.h:243
@ LB_TURBULENT_MIXING_INIT
Definition: enums.h:232
@ LB_TGV_INIT
Definition: enums.h:249
@ LB_LAMINAR_INIT_MY
Definition: enums.h:242
@ LB_STEADY_VORTEX_INIT
Definition: enums.h:254
@ LB_LAMINAR_INIT_MZ
Definition: enums.h:244
@ LB_LAMINAR_INIT_PY
Definition: enums.h:241
@ LB_LAMINAR_CHANNEL_INIT
Definition: enums.h:245
@ LB_LAMINAR_INIT_PX
Definition: enums.h:239
@ MAIA_LATTICE_BGK_TOTALENERGY
Definition: enums.h:86
void mTerm(const MInt errorCode, const MString &location, const MString &message)
Definition: functions.cpp:29
constexpr Real POW3(const Real x)
Definition: functions.h:123
constexpr Real POW2(const Real x)
Definition: functions.h:119
constexpr T mMin(const T &x, const T &y)
Definition: functions.h:90
T constexpr POWX(T base, MUint exponent)
Compile time power calculation.
Definition: functions.h:146
constexpr T mMax(const T &x, const T &y)
Definition: functions.h:94
MInt globalTimeStep
MInt globalNoDomains()
Return global number of domains.
MInt globalDomainId()
Return global domain id.
InfoOutFile m_log
std::ostream cerr0
constexpr MLong IPOW2(MInt x)
constexpr MFloat FPOW2(MInt x)
constexpr MFloat FPOW4(MInt x)
constexpr MFloat FFPOW2(MInt x)
int32_t MInt
Definition: maiatypes.h:62
std::basic_string< char > MString
Definition: maiatypes.h:55
double MFloat
Definition: maiatypes.h:52
long double MLongFloat
Definition: maiatypes.h:53
bool MBool
Definition: maiatypes.h:58
char MChar
Definition: maiatypes.h:56
MInt id
Definition: maiatypes.h:71
uint64_t MUlong
Definition: maiatypes.h:65
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_Barrier(MPI_Comm comm, const MString &name)
same as MPI_Barrier
int MPI_Gatherv(const void *sendbuf, int sendcount, MPI_Datatype sendtype, void *recvbuf, const int recvcounts[], const int displs[], MPI_Datatype recvtype, int root, MPI_Comm comm, const MString &name, const MString &sndvarname, const MString &rcvvarname)
same as MPI_Gatherv
int MPI_Reduce(const void *sendbuf, void *recvbuf, int count, MPI_Datatype datatype, MPI_Op op, int root, MPI_Comm comm, const MString &name, const MString &sndvarname, const MString &rcvvarname)
same as MPI_Reduce
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_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
int MPI_Alltoallv(const void *sendbuf, const int sendcounts[], const int sdispls[], MPI_Datatype sendtype, void *recvbuf, const int recvcounts[], const int rdispls[], MPI_Datatype recvtype, MPI_Comm comm, const MString &name, const MString &sndvarname, const MString &rcvvarname)
same as MPI_Alltoallv
int MPI_Send(const void *buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm, const MString &name, const MString &varname)
same as MPI_Send
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 ...
Definition: maiafftw.h:681
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.
Definition: maiafftw.h:892
MInt getGlobalPosFFTW(MInt i0, MInt i1, MInt i2, MInt ny, MInt nz)
Definition: maiafftw.h:59
MFloat dist(const Point< DIM > &p, const Point< DIM > &q)
Definition: pointbox.h:54
Definition: contexttypes.h:19
define array structures