MAIA bb96820c
Multiphysics at AIA
Loading...
Searching...
No Matches
lblpt.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 "lblpt.h"
8#include "LPT/lpt.h"
9#include "LPT/lptlib.h"
10
11using namespace std;
12using namespace maia::lpt;
13
14template <MInt nDim, MInt nDist, class SysEqn>
16 : Coupling(couplingId), CouplingLpt<nDim, CouplingLB<nDim, nDist, SysEqn>>(couplingId, particle, lb) {
17 TRACE();
18
19 m_particle = particle;
20 m_lbSolver = lb;
21
22 // get LPT-solver order
24 m_noSolverSteps = Context::getBasicProperty<MInt>("recipeMaxNoSteps", AT_, &m_noSolverSteps);
25 const MString propName = "solverOrder_" + std::to_string(lpt().solverId());
26 for(MInt step = 0; step < m_noSolverSteps; step++) {
27 if(Context::getBasicProperty<MInt>(propName, AT_, step) > 0) {
28 m_lptSolverOrder = step;
29 break;
30 }
31 }
32}
33
39template <MInt nDim, MInt nDist, class SysEqn>
41 TRACE();
42
43 m_lbSolverId = lbSolver().solverId();
44 m_lptSolverId = lpt().solverId();
45
46 readProperties();
47
48 checkProperties();
49
50 initConversion();
51
52 calculateGridBoundaries();
53}
54
59template <MInt nDim, MInt nDist, class SysEqn>
61 TRACE();
62 // TODO adjust:
63 // 1) read the following conversion factors as properties
64 MFloat lengthFactor = F1;
72 lengthFactor = Context::getSolverProperty<MFloat>("lengthFactor", lpt().solverId(), AT_, &lengthFactor);
73
74 MFloat velocityFactor = F1;
82 velocityFactor = Context::getSolverProperty<MFloat>("velocityFactor", lpt().solverId(), AT_, &velocityFactor);
83
84 MFloat viscosityFactor = F1;
92 viscosityFactor = Context::getSolverProperty<MFloat>("viscosityFactor", lpt().solverId(), AT_, &viscosityFactor);
93
94 const MFloat particleRe = Context::getSolverProperty<MFloat>("Re", lpt().solverId(), AT_);
95
96 // 2) compute the missing conversion factors
97 const MFloat ReFactor = lbSolver().m_Re / particleRe;
98 /*const */ MFloat densityFactor = ReFactor * lengthFactor / (velocityFactor * viscosityFactor);
99 /*const */ // MFloat temperatureFactor = sqrt(velocityFactor);
100
101 const MFloat dx = a_cellLengthAtLevel(lbSolver().maxLevel());
102
103 //---------------------------------------------------------------------------------------
104
105 if(lpt().m_Ma >= 0.3) mTerm(1, AT_, "LB-LPT assumes low Mach number!");
106
107 conversionLbLpt.velocity = velocityFactor * F1BCS / lbSolver().m_Ma;
108 conversionLptLb.velocity = F1 / conversionLbLpt.velocity;
109
110 conversionLbLpt.density = densityFactor;
111 conversionLptLb.density = F1 / conversionLbLpt.density;
112
113 conversionLbLpt.pressure = densityFactor * POW2(conversionLbLpt.velocity);
114 conversionLptLb.pressure = F1 / conversionLbLpt.pressure;
115
116 conversionLbLpt.length = lengthFactor * dx;
117 conversionLptLb.length = F1 / conversionLbLpt.length;
118
119 /* conversionLbLpt.temperature = temperatureFactor;
120 conversionLptLb.temperature = 1.0 / conversionLbLpt.temperature; */
121
122 conversionLbLpt.viscosity = viscosityFactor;
123 conversionLptLb.viscosity = F1 / conversionLbLpt.viscosity;
124
125 conversionLbLpt.time = conversionLbLpt.length / conversionLbLpt.velocity;
126 conversionLptLb.time = F1 / conversionLbLpt.time;
127
128 conversionLbLpt.mass = conversionLbLpt.velocity * conversionLbLpt.density * POW2(conversionLbLpt.length);
129 conversionLptLb.mass = F1 / conversionLbLpt.mass;
130
131 conversionLbLpt.momentum = conversionLbLpt.density * POW2(conversionLbLpt.velocity) * POW2(conversionLbLpt.length);
132 conversionLptLb.momentum = F1 / conversionLbLpt.momentum;
133
134 conversionLbLpt.energy = conversionLbLpt.density * POW3(conversionLbLpt.velocity) * POW2(conversionLbLpt.length);
135 conversionLptLb.energy = F1 / conversionLbLpt.energy;
136
137 if(lpt().domainId() == 0) {
138 cerr << "Lb-Lpt conversion factors are: " << endl;
139 cerr << "length : " << conversionLbLpt.length << endl;
140 cerr << "velocity : " << conversionLbLpt.velocity << endl;
141 cerr << "acceleration : " << conversionLbLpt.velocity / conversionLbLpt.time << endl;
142 cerr << "density : " << conversionLbLpt.density << endl;
143 cerr << "pressure : " << conversionLbLpt.pressure << endl;
144 cerr << "temperature : " << conversionLbLpt.temperature << endl;
145 cerr << "viscosity : " << conversionLbLpt.viscosity << endl;
146 cerr << "time : " << conversionLbLpt.time << endl;
147 cerr << "mass : " << conversionLbLpt.mass << endl;
148 cerr << "momentum : " << conversionLbLpt.momentum << endl;
149 cerr << "energy : " << conversionLbLpt.energy << endl;
150 }
151}
152
157template <MInt nDim, MInt nDist, class SysEqn>
159 TRACE();
160
161 MFloat halfCellWidth = 0.0;
162 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
163 if(!lbSolver().c_isLeafCell(cellId)) continue;
164 halfCellWidth = F1B2 * lbSolver().grid().cellLengthAtCell(cellId);
165 for(MInt i = 0; i < nDim; i++) {
166 m_gridBoundaries[2 * i] = mMin(m_gridBoundaries[2 * i], lbSolver().a_coordinate(cellId, i) - halfCellWidth);
167 m_gridBoundaries[2 * i + 1] =
168 mMax(m_gridBoundaries[2 * i + 1], lbSolver().a_coordinate(cellId, i) + halfCellWidth);
169 }
170 }
171
172 for(MInt i = 0; i < nDim; i++) {
173 MPI_Allreduce(MPI_IN_PLACE, &m_gridBoundaries[2 * i], 1, maia::type_traits<MFloat>::mpiType(), MPI_MIN,
174 lbSolver().mpiComm(), AT_, "MPI_IN_PLACE", "m_domainBoundaryMin");
175 MPI_Allreduce(MPI_IN_PLACE, &m_gridBoundaries[2 * i + 1], 1, maia::type_traits<MFloat>::mpiType(), MPI_MAX,
176 lbSolver().mpiComm(), AT_, "MPI_IN_PLACE", "m_domainBoundaryMax");
177 }
178}
179
185template <MInt nDim, MInt nDist, class SysEqn>
187 TRACE();
188
189 // TODO: inital velocity for ellipsoids
190 /* if(!lpt().m_restart) {
191 for(MInt i = 0; i < (MInt)lpt().m_partListEllipsoid.size(); i++) {
192 const MInt lptCellId = lpt().m_partListEllipsoid[i].m_cellId;
193 const MInt fvCellId = lpt2fvIdParent(lptCellId);
194 for(MInt j = 0; j < nDim; j++) {
195 lpt().m_partListEllipsoid[i].m_velocity[j] =
196 lpt().m_partListEllipsoid[i].m_velocity[j] + fvSolver().a_pvariable(fvCellId, j);
197 }
198 } */
199
200 // init fluid density and velocity, after the values have been transferred to the LPT solver!
201 for(MInt i = 0; i < lpt().a_noParticles(); i++) {
202 lpt().m_partList[i].initVelocityAndDensity();
203 }
204}
205
211template <MInt nDim, MInt nDist, class SysEqn>
213 TRACE();
214
215 // Transfer the flow field after the intial condition for LB has been applied
216 transferFlowField();
217 transferCellStatus();
218
219 initParticleVelocity();
220
221 // TODO: check
222 if(!lpt().m_restartFile && lbSolver().m_restartFile) {
223 if(lpt().domainId() == 0) {
224 cerr << "Restart without LPT restartFile -> setting time from Lb-time!" << endl;
225 }
226 const MFloat conversionTime = conversionLbLpt.length / conversionLbLpt.velocity;
227 const MFloat LbTime = lbSolver().m_time;
228 lpt().m_time = LbTime * conversionTime;
229 }
230
231 // set the timeStep in the LPT solver
232 // at this point the timeStep must be enforced by the lb-solver
233 transferTimeStep();
234}
235
240template <MInt nDim, MInt nDist, class SysEqn>
242 TRACE();
243
244 m_lptlbInterpolation =
245 Context::getSolverProperty<MBool>("allowLPTlbInterpolation", m_lbSolverId, AT_, &m_lptlbInterpolation);
246
259 // m_forceLbTimeStep = true;
260 m_forceLbTimeStep = Context::getSolverProperty<MBool>("forceLbTimeStep", m_lptSolverId, AT_, &m_forceLbTimeStep);
261
262 m_CalcSurface = Context::getSolverProperty<MBool>("couplerCalcSurface", m_lptSolverId, AT_, &m_CalcSurface);
263
264 /* if(!m_forceLbTimeStep && !m_interLeafed) {
265 mTerm(1, AT_, "Coupled timesteps only working with interleafed setup!");
266 } */
267}
268
274template <MInt nDim, MInt nDist, class SysEqn>
276 TRACE();
277
278 cout << "in lblpt.cpp: m_Re = " << lpt().m_Re << " m_Re= " << lpt().m_Re << " m_Ma = " << lpt().m_Ma << "\n";
279 const MFloat lptRe = Context::getSolverProperty<MFloat>("Re", lpt().solverId(), AT_);
280
281 cout << "in lblpt.cpp lptRe = " << lptRe << "\n";
282
283 // ASSERT(fabs(lptRe - lbSolver().m_Re) < MFloatEps, "LPT: " << lptRe << " LB " << lbSolver().m_Re);
284 if(fabs(lptRe - lbSolver().m_Re) > MFloatEps) {
285 cerr << "Warning: Re0 differs between lb- and LPT-solver!"
286 << " lb " << lbSolver().m_Re << " LPT " << lptRe << endl;
287 }
288
289 // TODO:
290 // ASSERT(lpt().a_timeStepComputationInterval() == fvSolver().a_timeStepComputationInterval(), "");
291}
292
301template <MInt nDim, MInt nDist, class SysEqn>
303 TRACE();
304
305 // PRE LPT
306 if(recipeStep == m_lptSolverOrder) {
307 // TODO m_solutionStep = 0;
308
309 // TODO:
310 /* if(fvSolver().m_hasExternalSource) {
311 if(!m_interLeafed) lbSolver().resetExternalSources();
312 } */
313 if(lbSolver().m_particleMomentumCoupling) lbSolver().resetExternalSources();
314
315 // update LPT bndryCells for wall-collision
316 updateLPTBndry();
317 }
318
319 // TODO: implement for interleaved
320 /* if(m_interLeafed) {
321 const MFloat conversionTime = conversionFvLpt.length / conversionFvLpt.velocity;
322 const MFloat fvTime = fvSolver().m_levelSetMb ? fvSolver().m_physicalTime : fvSolver().m_time;
323 if(fabs(fvTime * conversionTime - lpt().m_time) > MFloatEps) {
324 cerr << "LPT-time " << lpt().m_time << " Fv-time " << fvTime << endl;
325 mTerm(1, AT_, "Miss-matching time!");
326 }
327 } */
328}
329
340template <MInt nDim, MInt nDist, class SysEqn>
342 TRACE();
343
344 // recipe-order is switched for ellipsoids
345 // if(lpt().m_ellipsoids) {
346 // recipeStep = recipeStep == 1 ? 0 : 1;
347 //}
348
349 // Post LPT (as the LPT-solver is called before the lb-solver!)
350 if(recipeStep == m_lptSolverOrder) {
351 updateLbSolver();
352 }
353
354 // POST LB
355 MInt postLbStep = m_lptSolverOrder < m_noSolverSteps - 1 ? m_lptSolverOrder + 1 : m_lptSolverOrder - 1;
356 if(recipeStep == postLbStep) {
357 transferFlowField();
358
359 transferCellStatus();
360 transferTimeStep();
361
362 // set particle velocity to fluid velocity in first timestep or in TimeStep in which desired velocitySkewness is
363 // reached
364 if((!(lpt().m_skewnessTimeStep == -1) && (globalTimeStep == 1 && lpt().m_skewnessTimeStep == 0))
365 || (globalTimeStep == lpt().m_skewnessTimeStep)) {
366 for(auto& part : lpt().m_partList) {
367 for(MInt i = 0; i < nDim; i++) {
368 MInt lbCellId = lpt2lbId(part.m_cellId);
369 part.m_velocity[i] = part.m_oldVel[i] =
370 lbSolver().a_variable(lbCellId, lbSolver().PV->VV[i]) * conversionLbLpt.velocity;
371 }
372 }
373 }
374 }
375}
376
380template <MInt nDim, MInt nDist, class SysEqn>
382 TRACE();
383
384 std::cout << "in finalize Balance" << std::endl;
385 // post LPT solver
386 if(id == lpt().solverId()) {
387 lbSolver().resetExternalSources();
388 if(globalTimeStep < 0) {
389 // prepareAdaptation();
390 }
391
392 } else if(id == lbSolver().solverId()) {
393 transferFlowField();
394 transferCellStatus();
395
396 updateLPTBndry();
397 }
398}
399
405template <MInt nDim, MInt nDist, class SysEqn>
407 TRACE();
408
409 // transfer external Sources to LB-solver
410 if(!lbSolver().isActive() || !lpt().m_momentumCoupling) return;
411
412 // check if noInternalCells must be used
413#ifdef _OPENMP
414#pragma omp parallel for
415#endif
416 for(MInt lbCellId = 0; lbCellId < lbSolver().a_noCells(); lbCellId++) {
417 if(!lbSolver().a_isActive(lbCellId)) continue;
418 // check that externalForces is set to zeros
419 for(MInt i = 0; i < nDim; i++)
420 ASSERT(abs(lbSolver().a_externalForces(lbCellId, i)) < MFloatEps, "");
421 }
422
423 // TODO: interleaved
424 /*
425 const MInt lbMaxLevel = lbSolver().maxLevel();
426 #ifdef _OPENMP
427 #pragma omp parallel for
428 #endif
429 for(MInt lptCell = 0; lptCell < lpt().a_noCells(); lptCell++) {
430 // TODO-timw: check lpt-exchange! use below instead
431 // for(MInt lptCell = 0; lptCell < lpt().noInternalCells(); lptCell++) {
432 // the source term is only set on LPT leaf-cells
433 if(!lpt().c_isLeafCell(lptCell)) continue;
434 // TODO: always keep noParticles in cell up to date,
435 // so that cells without particles easily be skipped
436 MInt lbCellId = lpt2lbId(lptCell);
437 if(lbCellId > -1 && lbSolver().c_isLeafCell(lbCellId)) {
438 const MInt lbLevel = lbSolver().a_level(lbCellId);
439 const MFloat fLbCellVolume = FFPOW2(lbMaxLevel - lbLevel);
440 // simple transfer
441 for(MInt dir = 0; dir < nDim; dir++) {
442 lbSolver().a_externalForces(lbCellId, dir) -=
443 lpt().a_momentumFlux(lptCell, dir) * conversionLptLb.momentum * fLbCellVolume * m_factor;
444 if(abs(lpt().a_momentumFlux(lptCell, dir)) > 1e-5)
445 std::cerr << "lbforce " << lbSolver().a_externalForces(lbCellId, dir) << " conv " <<
446 conversionLptLb.momentum
447 << " fLbCV " << fLbCellVolume << " flux " << lpt().a_momentumFlux(lptCell, dir) << std::endl;
448 }
449 }
450 }
451 */
452
453#ifdef _OPENMP
454#pragma omp parallel for
455#endif
456 for(MInt lptCellId = 0; lptCellId < lpt().a_noCells(); lptCellId++) {
457 if(!lpt().c_isLeafCell(lptCellId)) continue;
458 const MInt lbCellId = lpt2lbId(lptCellId);
459 if(lbCellId < 0) continue;
460 if(lbCellId > -1 && lbSolver().c_isLeafCell(lbCellId)) {
461 for(MInt i = 0; i < nDim; i++) {
462 // Think about different refinement levels of lb-cells and lpt-cells like in fvparticle.cpp ->
463 // transferExternalSources()
464 // obtain reaction force density related to cellvolume in lb-Units acting on fluid
465 lbSolver().a_externalForces(lbCellId, i) -= lpt().a_momentumFlux(lptCellId, i) * conversionLptLb.momentum;
466 }
467 }
468 // TODO different refinement of LPT an LB
469 }
470 lbSolver().exchangeExternalSources();
471}
472
473// TODO: implement interleaved version
477/*template <MInt nDim, MInt nDist, class SysEqn>
478void LbLpt<nDim, nDist, SysEqn>::updateForcing() {
479 TRACE();
480
481 if(!lbSolver().isActive()) return;
482
483 if(!lpt().m_momentumCoupling && !lpt().m_heatCoupling && !lpt().m_massCoupling) return;
484
485 // TODO-timw: check lpt-exchange! add
486 // lpt().exchangeSourceTerms();
487
488#ifdef _OPENMP
489#pragma omp parallel for
490#endif
491 for(MInt cellId = 0; cellId < lbSolver().a_noCells(); cellId++) {
492 for(MInt var = 0; var < nDim; var++) {
493 lbSolver().a_cellForce(cellId, var) = 0.0;
494 }
495 }
496
497 const MInt lbMaxLevel = lbSolver().maxLevel();
498#ifdef _OPENMP
499#pragma omp parallel for
500#endif
501 for(MInt lptCell = 0; lptCell < lpt().a_noCells(); lptCell++) {
502 // TODO-timw: check lpt-exchange! use below instead
503 // for(MInt lptCell = 0; lptCell < lpt().noInternalCells(); lptCell++) {
504 // the source term is only set on LPT leaf-cells
505 if(!lpt().c_isLeafCell(lptCell)) continue;
506 // TODO: always keep noParticles in cell up to date,
507 // so that cells without particles easily be skipped
508 MInt lbCellId = lpt2lbId(lptCell);
509 if(lbCellId > -1 && lbSolver().c_isLeafCell(lbCellId)) {
510 const MInt lbLevel = lbSolver().a_level(lbCellId);
511 const MFloat fLbCellVolume = FFPOW2(lbMaxLevel - lbLevel);
512 // simple transfer
513 for(MInt dir = 0; dir < nDim; dir++) {
514 lbSolver().a_cellForce(lbCellId, dir) -=
515 lpt().a_momentumFlux(lptCell, dir) * conversionLptLb.momentum * fLbCellVolume;
516 // if(abs(lpt().a_momentumFlux(lptCell, dir)) > 1e-5)
517 // std::cerr << "lbforce " << lbSolver().a_cellForce(lbCellId, dir) << " conv " << conversionLptLb.momentum
518 // << " fLbCV " << fLbCellVolume << " flux " << lpt().a_momentumFlux(lptCell, dir) << std::endl;
519 }
520
521 } else if(lbCellId > -1 && !lbSolver().c_isLeafCell(lbCellId)) {
522 // lb-cell is refined further: volume average from LPT to LB
523 if(lpt().a_isHalo(lptCell)) continue;
524 // gather all lb-leaf-cell childs for internal cells
525 vector<MInt> leafChildIds;
526 lbSolver().grid().getAllLeafChilds(lbCellId, leafChildIds);
527 MFloat totalVol = 0;
528 for(MUint i = 0; i < leafChildIds.size(); i++) {
529 const MInt cellId = leafChildIds[i];
530 totalVol += lbSolver().grid().cellVolumeAtLevel(lbSolver().c_level(cellId));
531 }
532 for(MUint i = 0; i < leafChildIds.size(); i++) {
533 const MInt cellId = leafChildIds[i];
534 const MInt lbLevel = lbSolver().a_level(cellId);
535 const MFloat fLbCellVolume = FFPOW2(lbMaxLevel - lbLevel);
536 const MFloat vFrac = lbSolver().grid().cellVolumeAtLevel(lbSolver().c_level(cellId)) / totalVol;
537 for(MInt dir = 0; dir < nDim; dir++) {
538 lbSolver().a_cellForce(cellId, dir) -=
539 lpt().a_momentumFlux(lptCell, dir) * vFrac * conversionLptLb.momentum * fLbCellVolume;
540 }
541 }
542 } else {
543 mTerm(1, AT_, "check if race condition exists here!");
544 // lpt-Cell is refined further
545 lbCellId = lpt2lbIdParent(lptCell);
546 if(lbCellId < 0) continue;
547 const MInt lbLevel = lbSolver().a_level(lbCellId);
548 const MFloat fLbCellVolume = FFPOW2(lbMaxLevel - lbLevel);
549 vector<MInt> leafChildIds;
550 lpt().grid().getAllLeafChilds(lptCell, leafChildIds);
551
552 // calculate sum of all source terms from all lpt leaf cells
553 for(MUint i = 0; i < leafChildIds.size(); i++) {
554 const MInt cellId = leafChildIds[i];
555 for(MInt dir = 0; dir < nDim; dir++) {
556 lbSolver().a_cellForce(lbCellId, dir) -=
557 lpt().a_momentumFlux(cellId, dir) * conversionLptLb.momentum * fLbCellVolume;
558 }
559 }
560 }
561 }
562}
563*/
564
570template <MInt nDim, MInt nDist, class SysEqn>
572 TRACE();
573#ifdef _OPENMP
574#pragma omp parallel for
575#endif
576 for(MInt lbCellId = 0; lbCellId < lbSolver().noInternalCells(); lbCellId++) {
577 if(!lbSolver().a_isActive(lbCellId)) {
578 continue;
579 }
580
581 const MInt lptCellId = lb2lptId(lbCellId);
582 if(lptCellId < 0) continue;
583
584 for(MInt n = 0; n < nDim; n++) {
585 lpt().a_fluidVelocity(lptCellId, n) =
586 lbSolver().a_variable(lbCellId, lbSolver().PV->VV[n]) * conversionLbLpt.velocity;
587 }
588 lpt().a_fluidDensity(lptCellId) = conversionLbLpt.density * lbSolver().a_variable(lbCellId, lbSolver().PV->RHO);
589
590 // Assume incompressible LB
591 lpt().a_fluidPressure(lptCellId) =
592 (lbSolver().a_variable(lbCellId, lbSolver().PV->RHO) - 1.0) * F1B3 * conversionLbLpt.pressure + 1.0;
593 // TODO: @Julian reactivate for thermal
594 /*lpt().a_fluidTemperature(lptCellId) = lbSolver().a_pvariable(lbCellId, lbSolver().PV->T)
595 * conversionLbLpt.temperature;*/
596 }
597
598 // NOTE: exchange is necessary as particles on window-cells interpolate the flow variables to their
599 // position and will need values on halo-cells to do so!
600 lpt().exchangeData(&lpt().a_fluidVariable(0, 0), lpt().PV.noVars());
601 if(lpt().m_evaporation) {
602 lpt().exchangeData(&lpt().a_fluidSpecies(0), 1);
603 }
604
605 lpt().checkCells();
606}
607
613template <MInt nDim, MInt nDist, class SysEqn>
615 TRACE();
616
617 if(!lpt().m_wallCollisions) return;
618
619 if(!lpt().isActive()) return;
620
621 MFloatScratchSpace bBox(2 * nDim, AT_, "bBox");
622 lbSolver().m_geometry->getBoundingBox(bBox.getPointer());
623
624 /*
625 using Ld = LbLatticeDescriptor<nDim, nDist>;
626 // just number of 2D distributions
627 static constexpr MInt dist1 = Ld::distFld(0);
628 static constexpr MInt maxDist1Idx = dist1; // for loops
629 static constexpr MInt dist2 = Ld::distFld(1);
630 static constexpr MInt maxDist2Idx = dist1 + dist2; // for loops
631 */
632 // Just once if no mesh adaptation during run
633 for(MInt bndryId = lbSolver().m_noOuterBndryCells; bndryId < a_noBndCells(); bndryId++) {
634 const MInt lbCellId = a_bndCellId(bndryId);
635
636 if(!lbSolver().c_isLeafCell(lbCellId)) continue;
637 MInt lptCellId = lb2lptId(lbCellId);
638 if(lptCellId < 0) {
639 lptCellId = lb2lptIdParent(lbCellId);
640 if(lptCellId < 0) continue;
641 if(lpt().c_level(lptCellId) < lpt().maxRefinementLevel()) continue;
642 ASSERT(m_lptlbInterpolation, "");
643 }
644
645 if(!lpt().c_isLeafCell(lptCellId)) {
646 ASSERT(m_lptlbInterpolation, "");
647 }
648
649 const MInt noSurf = 1; // lbSolver().m_bndCnd->m_bndCells->a[bndryId].m_noSrfcs
650
651 // bndryCell without a bndrySurface, how is that even possible?
652 // if(noSurf < 1 ) continue;
653
654 ASSERT(noSurf == 1, "Only for single bndry-surfaces!");
655
656 MFloatScratchSpace surfaceC(nDim, nDim + 1, AT_, "surfaceC");
657 std::array<MFloat, nDim> surfaceN;
658 std::array<MFloat, nDim> surfaceV;
659 std::array<MFloat, nDim + 1> bndryData;
660
661 // TODO: check correctness of addbndryCellMethod before reusing!
662 /* if(m_CalcSurface) {
663 const MFloat dx = lbSolver().c_cellLengthAtCell(lbCellId);
664 std::vector<const MFloat*> cellWallNormals; // store all Wall normals
665 std::vector<const MFloat*>
666 cellPlaneCoordinateVec; // 2D Distribution from cell center to point in the middle of an surface edge
667 const MFloat* SCdist{};
668 MInt wallCount = 0;
669 std::array<MBool, nDim> gridBoxDifference{};
670
671 for(MInt i = 0; i < nDim; i++) {
672 bndryData.at(1 + i) = lbSolver().a_coordinate(lbCellId, i);
673 }
674
675 for(MInt j = 0; j < maxDist1Idx; j++) {
676 if(lbSolver().a_hasNeighbor(lbCellId, j) == 0) {
677 SCdist = Ld::ppdfDir(j); // only for 1D, dist from cell center to SC
678 cellWallNormals.push_back(Ld::ppdfDir(Ld::oppositeDist(j)));
679 wallCount++;
680 }
681 }
682
683 // compute surface normals out of cellWallNormals, should be independent from number of distributions
684 for(MInt n = 0; n < nDim; n++) {
685 surfaceV.at(n) = 0; // for simple simulation not needed, can be set to zero;
686 for(size_t a = 0; a < cellWallNormals.size(); a++)
687 surfaceN.at(n) += cellWallNormals.at(a)[n]; // Assuming wallnormals have just one vec component unequal 0
688 }
689 maia::math::normalize(surfaceN);
690
691 switch(wallCount) {
692 case 0:
693 std::cerr << "Something went wrong, " << lbCellId << " is not a boundaryCell" << std::endl;
694 break;
695
696 case 1:
697 // set bndry-cell volume:
698 bndryData.at(0) = POW3(dx);
699 // Iterate over 2D distributions
700 for(MInt j = maxDist1Idx; j < maxDist2Idx; j++) {
701 for(MInt n = 0; n < nDim; n++) {
702 // Check for -1 * -1 or 1 * 1; -1 * 1 should not pass since SCdist[n] and ppdf(j,n) are not equal.
703 if(SCdist[n] * Ld::ppdfDir(j, n) + MFloatEps > 1.0) {
704 cellPlaneCoordinateVec.push_back(Ld::ppdfDir(j));
705 if(cellPlaneCoordinateVec.size() == 3) break; // only 3 points are needed
706 }
707 }
708 }
709
710 for(MInt n = 0; n < nDim; n++) {
711 gridBoxDifference.at(n) = false;
712 surfaceC.at(0).at(n) = bndryData.at(1 + n) - surfaceN.at(n) * dx / 2;
713 if(surfaceN.at(n) > 0.0) {
714 if(bBox[n] > m_gridBoundaries[2 * n]) {
715 surfaceC.at(0).at(n) = bBox[n];
716 gridBoxDifference.at(n) = true;
717 }
718 } else if(surfaceN.at(n) < 0.0) {
719 if(bBox[n + nDim] < m_gridBoundaries[2 * n + 1]) {
720 surfaceC.at(0).at(n) = bBox[n + nDim];
721 gridBoxDifference.at(n) = true;
722 }
723 }
724 }
725 break;
726
727 case 2:
728 // set bndry-cell volume:
729 bndryData.at(0) = POW3(dx) / 2;
730 // Iterate over 1D and 2D distributions
731 for(MInt j = 0; j < maxDist2Idx; j++) {
732 std::array<MFloat, nDim> tmpDist{};
733 for(MInt n = 0; n < nDim; n++) {
734 tmpDist[n] = Ld::ppdfDir(j, n);
735 }
736 // search for 1D and 2D distributions that are perpendicular to surface normal vector
737 if(abs(std::inner_product(surfaceN.cbegin(), surfaceN.cend(), tmpDist.cbegin(), 0.0)) < MFloatEps)
738 cellPlaneCoordinateVec.push_back(Ld::ppdfDir(j));
739 if(cellPlaneCoordinateVec.size() == 3) break;
740 }
741
742 for(MInt n = 0; n < nDim; n++) {
743 surfaceC.at(0).at(n) = bndryData.at(1 + n);
744 }
745 break;
746
747 case 3:
748 // set bndry-cell volume:
749 bndryData.at(0) = POW3(dx) * (1.0 - 0.25 * (0.5 * SQRT3 - sqrt(3 - SQRT6)));
750 // Iterate over 1D distributions
751 for(MInt j = 0; j < maxDist1Idx; j++) {
752 std::array<MFloat, nDim> tmpDist{};
753 for(MInt n = 0; n < nDim; n++) {
754 tmpDist[n] = Ld::ppdfDir(j, n);
755 }
756 // search for 1D distributions that are pointing in opposite halfspace of surface normal -> va * vb = abs(a)
757 // * abs(b) * cos(phi) < 0 -> yes
758 if(std::inner_product(surfaceN.cbegin(), surfaceN.cend(), tmpDist.cbegin(), 0.0) < MFloatEps)
759 cellPlaneCoordinateVec.push_back(Ld::ppdfDir(j));
760 if(cellPlaneCoordinateVec.size() == 3) break;
761 }
762
763 for(MInt n = 0; n < nDim; n++) {
764 surfaceC.at(0).at(n) = bndryData.at(1 + n) - surfaceN.at(n) * sqrt(3 - SQRT6) * dx; //? check
765 }
766 break;
767
768 default:
769 std::cerr << "No implementation for cells with more than 3 bounding walls!" << std::endl;
770 break;
771 }
772
773 // find 3 Distributions to get 3 points on surface edges
774 MFloat dL = 0.0;
775 // loop over coordinate x,y,z
776 for(MInt i = 0; i < nDim; i++) {
777 if(gridBoxDifference.at(i))
778 dL = bndryData.at(1 + i) - surfaceC.at(0).at(i);
779 else
780 dL = dx / 2;
781 // loop over surface point 1,2,3
782 for(MInt n = 0; n < nDim; n++) {
783 surfaceC.at(1 + n).at(i) = bndryData.at(1 + i) + cellPlaneCoordinateVec.at(n)[i] * dL;
784 }
785 } */
786 // Printing boundary surface information :
787 /* std::cout << "lbcellId: " << lbCellId << std::endl
788 << "lptcellId: " << lptCellId << std::endl
789 << "wallCount: " << wallCount << std::endl
790 << "bndrycell Volume: " << bndryData.at(0) << std::endl;
791 for(MInt i = 0; i < nDim; i++) std::cout << "bndryData[" << bndryId << "].m_coordinates "<< i << ": " <<
792 bndryData.at(1 + i) << std::endl; for(MInt i = 0; i < nDim; i++) std::cout << "surfaceN[ " << i << "] normalized:
793 " << surfaceN.at(i) << std::endl; for(MInt i = 0; i < nDim; i++) std::cout << "surfaceC[0][" << i << "]: " <<
794 surfaceC.at(0).at(i) << std::endl;
795
796 for(MInt i = 0; i < nDim; i++)
797 for(MInt n = 0; n <nDim; n++)
798 std::cout << "cellPlaneCoordinateVec[" << i <<"]["<<n<<"]: " << cellPlaneCoordinateVec.at(i)[n] << std::endl;
799 for(MInt i = 0; i < nDim; i++)
800 for(MInt n = 0; n <nDim; n++)
801 std::cout << "surfaceC[" << 1 + i << "]["<< n << "]: " << surfaceC.at(1 + i).at(n) << std::endl;
802 */
803
804 // clear all temporary vectors
805 /* cellWallNormals.clear();
806 cellPlaneCoordinateVec.clear();
807 } */
808 // append new LPT bndryCell based on LB data
809 lpt().addBndryCell(lptCellId, &bndryData[0], &surfaceN[0], surfaceC, &surfaceV[0]);
810 }
811}
812
816template <MInt nDim, MInt nDist, class SysEqn>
818 TRACE();
819
820 lpt().forceTimeStep(/*fvSolver().timeStep(true) */ conversionLbLpt.time);
821}
822
823// TODO:
827template <MInt nDim, MInt nDist, class SysEqn>
829 TRACE();
830 for(MInt lptCellId = 0; lptCellId < lpt().a_noCells(); lptCellId++) {
831 MInt lbCellId = lpt2lbIdParent(lptCellId);
832 if(lbCellId < 0 || lbCellId > lbSolver().a_noCells()) {
833 lpt().a_isValidCell(lptCellId) = false;
834 } else if(!lbSolver().a_isActive(lbCellId)) {
835 lpt().a_isValidCell(lptCellId) = false;
836 } else {
837 lpt().a_isValidCell(lptCellId) = true;
838 }
839 }
840}
841
842// Explicit instantiations
Definition: lpt.h:82
Definition: lblpt.h:30
void preCouple(MInt) override
Coupling before each solver.
Definition: lblpt.cpp:302
LPT< nDim > & lpt() const override
Definition: lblpt.h:43
LbSolver * m_lbSolver
Definition: lblpt.h:114
LbLpt(const MInt couplingId, LPT< nDim > *particle, LbSolver *lb)
Definition: lblpt.cpp:15
void checkProperties() override
Check coupler properties for validity.
Definition: lblpt.cpp:275
void initParticleVelocity()
Sets the initial particle velocity based on the flow field velocity in that cell. NOTE: This can not ...
Definition: lblpt.cpp:186
void postCouple(MInt) override
Coupling after each solver.
Definition: lblpt.cpp:341
void readProperties()
void transferCellStatus()
set the isValid status for LPT cells based on the FV-solver cell properties
Definition: lblpt.cpp:828
void transferFlowField()
Transfer the momentum source (forcing) from LPT to LB.
Definition: lblpt.cpp:571
void updateLbSolver()
Transfer all relevant data from LPT to LB solver.
Definition: lblpt.cpp:406
void transferTimeStep()
transfer/enforce Fv timeStep onto LPT solver
Definition: lblpt.cpp:817
void init() override
Init coupling class.
Definition: lblpt.cpp:40
MInt m_lptSolverOrder
Definition: lblpt.h:118
void finalizeBalance(const MInt) override
postCouple: exchange source terms after the LPT timeStep
Definition: lblpt.cpp:381
void finalizeCouplerInit() override
Finalize coupler initialization, coupler is ready after this.
Definition: lblpt.cpp:212
LPT< nDim > * m_particle
Definition: lblpt.h:113
void initConversion()
void calculateGridBoundaries()
calculate Boundaries of box-shaped Grid for calculation of boundaryCellData
Definition: lblpt.cpp:158
void updateLPTBndry()
Transfer all relevant bndryCell-data from LB to LPT.
Definition: lblpt.cpp:614
MInt m_noSolverSteps
Definition: lblpt.h:119
This class is a ScratchSpace.
Definition: scratch.h:758
T * getPointer() const
Deprecated: use begin() instead!
Definition: scratch.h:316
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
constexpr T mMax(const T &x, const T &y)
Definition: functions.h:94
MInt globalTimeStep
int32_t MInt
Definition: maiatypes.h:62
std::basic_string< char > MString
Definition: maiatypes.h:55
double MFloat
Definition: maiatypes.h:52
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
Definition: lpt.h:47