14template <MInt nDim, MInt nDist,
class SysEqn>
25 const MString propName =
"solverOrder_" + std::to_string(
lpt().solverId());
27 if(Context::getBasicProperty<MInt>(propName, AT_, step) > 0) {
39template <MInt nDim, MInt nDist,
class SysEqn>
43 m_lbSolverId = lbSolver().solverId();
44 m_lptSolverId = lpt().solverId();
52 calculateGridBoundaries();
59template <MInt nDim, MInt nDist,
class SysEqn>
72 lengthFactor = Context::getSolverProperty<MFloat>(
"lengthFactor", lpt().solverId(), AT_, &lengthFactor);
74 MFloat velocityFactor = F1;
82 velocityFactor = Context::getSolverProperty<MFloat>(
"velocityFactor", lpt().solverId(), AT_, &velocityFactor);
84 MFloat viscosityFactor = F1;
92 viscosityFactor = Context::getSolverProperty<MFloat>(
"viscosityFactor", lpt().solverId(), AT_, &viscosityFactor);
94 const MFloat particleRe = Context::getSolverProperty<MFloat>(
"Re", lpt().solverId(), AT_);
97 const MFloat ReFactor = lbSolver().m_Re / particleRe;
98 MFloat densityFactor = ReFactor * lengthFactor / (velocityFactor * viscosityFactor);
101 const MFloat dx = a_cellLengthAtLevel(lbSolver().maxLevel());
105 if(lpt().m_Ma >= 0.3)
mTerm(1, AT_,
"LB-LPT assumes low Mach number!");
107 conversionLbLpt.velocity = velocityFactor * F1BCS / lbSolver().m_Ma;
108 conversionLptLb.velocity = F1 / conversionLbLpt.velocity;
110 conversionLbLpt.density = densityFactor;
111 conversionLptLb.density = F1 / conversionLbLpt.density;
113 conversionLbLpt.pressure = densityFactor *
POW2(conversionLbLpt.velocity);
114 conversionLptLb.pressure = F1 / conversionLbLpt.pressure;
116 conversionLbLpt.length = lengthFactor * dx;
117 conversionLptLb.length = F1 / conversionLbLpt.length;
122 conversionLbLpt.viscosity = viscosityFactor;
123 conversionLptLb.viscosity = F1 / conversionLbLpt.viscosity;
125 conversionLbLpt.time = conversionLbLpt.length / conversionLbLpt.velocity;
126 conversionLptLb.time = F1 / conversionLbLpt.time;
128 conversionLbLpt.mass = conversionLbLpt.velocity * conversionLbLpt.density *
POW2(conversionLbLpt.length);
129 conversionLptLb.mass = F1 / conversionLbLpt.mass;
131 conversionLbLpt.momentum = conversionLbLpt.density *
POW2(conversionLbLpt.velocity) *
POW2(conversionLbLpt.length);
132 conversionLptLb.momentum = F1 / conversionLbLpt.momentum;
134 conversionLbLpt.energy = conversionLbLpt.density *
POW3(conversionLbLpt.velocity) *
POW2(conversionLbLpt.length);
135 conversionLptLb.energy = F1 / conversionLbLpt.energy;
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;
157template <MInt nDim, MInt nDist,
class SysEqn>
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);
172 for(
MInt i = 0; i < nDim; i++) {
174 lbSolver().mpiComm(), AT_,
"MPI_IN_PLACE",
"m_domainBoundaryMin");
176 lbSolver().mpiComm(), AT_,
"MPI_IN_PLACE",
"m_domainBoundaryMax");
185template <MInt nDim, MInt nDist,
class SysEqn>
201 for(
MInt i = 0; i < lpt().a_noParticles(); i++) {
202 lpt().m_partList[i].initVelocityAndDensity();
211template <MInt nDim, MInt nDist,
class SysEqn>
217 transferCellStatus();
219 initParticleVelocity();
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;
226 const MFloat conversionTime = conversionLbLpt.length / conversionLbLpt.velocity;
227 const MFloat LbTime = lbSolver().m_time;
228 lpt().m_time = LbTime * conversionTime;
240template <MInt nDim, MInt nDist,
class SysEqn>
244 m_lptlbInterpolation =
245 Context::getSolverProperty<MBool>(
"allowLPTlbInterpolation", m_lbSolverId, AT_, &m_lptlbInterpolation);
260 m_forceLbTimeStep = Context::getSolverProperty<MBool>(
"forceLbTimeStep", m_lptSolverId, AT_, &m_forceLbTimeStep);
262 m_CalcSurface = Context::getSolverProperty<MBool>(
"couplerCalcSurface", m_lptSolverId, AT_, &m_CalcSurface);
274template <MInt nDim, MInt nDist,
class SysEqn>
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_);
281 cout <<
"in lblpt.cpp lptRe = " << lptRe <<
"\n";
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;
301template <MInt nDim, MInt nDist,
class SysEqn>
306 if(recipeStep == m_lptSolverOrder) {
313 if(lbSolver().m_particleMomentumCoupling) lbSolver().resetExternalSources();
340template <MInt nDim, MInt nDist,
class SysEqn>
350 if(recipeStep == m_lptSolverOrder) {
355 MInt postLbStep = m_lptSolverOrder < m_noSolverSteps - 1 ? m_lptSolverOrder + 1 : m_lptSolverOrder - 1;
356 if(recipeStep == postLbStep) {
359 transferCellStatus();
364 if((!(lpt().m_skewnessTimeStep == -1) && (
globalTimeStep == 1 && lpt().m_skewnessTimeStep == 0))
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;
380template <MInt nDim, MInt nDist,
class SysEqn>
384 std::cout <<
"in finalize Balance" << std::endl;
386 if(
id == lpt().solverId()) {
387 lbSolver().resetExternalSources();
392 }
else if(
id == lbSolver().solverId()) {
394 transferCellStatus();
405template <MInt nDim, MInt nDist,
class SysEqn>
410 if(!lbSolver().isActive() || !lpt().m_momentumCoupling)
return;
414#pragma omp parallel for
416 for(
MInt lbCellId = 0; lbCellId < lbSolver().a_noCells(); lbCellId++) {
417 if(!lbSolver().a_isActive(lbCellId))
continue;
419 for(
MInt i = 0; i < nDim; i++)
420 ASSERT(abs(lbSolver().a_externalForces(lbCellId, i)) < MFloatEps,
"");
454#pragma omp parallel for
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++) {
465 lbSolver().a_externalForces(lbCellId, i) -= lpt().a_momentumFlux(lptCellId, i) * conversionLptLb.momentum;
470 lbSolver().exchangeExternalSources();
570template <MInt nDim, MInt nDist,
class SysEqn>
574#pragma omp parallel for
576 for(
MInt lbCellId = 0; lbCellId < lbSolver().noInternalCells(); lbCellId++) {
577 if(!lbSolver().a_isActive(lbCellId)) {
581 const MInt lptCellId = lb2lptId(lbCellId);
582 if(lptCellId < 0)
continue;
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;
588 lpt().a_fluidDensity(lptCellId) = conversionLbLpt.density * lbSolver().a_variable(lbCellId, lbSolver().PV->RHO);
591 lpt().a_fluidPressure(lptCellId) =
592 (lbSolver().a_variable(lbCellId, lbSolver().PV->RHO) - 1.0) * F1B3 * conversionLbLpt.pressure + 1.0;
600 lpt().exchangeData(&lpt().a_fluidVariable(0, 0), lpt().PV.noVars());
601 if(lpt().m_evaporation) {
602 lpt().exchangeData(&lpt().a_fluidSpecies(0), 1);
613template <MInt nDim, MInt nDist,
class SysEqn>
617 if(!lpt().m_wallCollisions)
return;
619 if(!lpt().isActive())
return;
622 lbSolver().m_geometry->getBoundingBox(bBox.
getPointer());
633 for(
MInt bndryId = lbSolver().m_noOuterBndryCells; bndryId < a_noBndCells(); bndryId++) {
634 const MInt lbCellId = a_bndCellId(bndryId);
636 if(!lbSolver().c_isLeafCell(lbCellId))
continue;
637 MInt lptCellId = lb2lptId(lbCellId);
639 lptCellId = lb2lptIdParent(lbCellId);
640 if(lptCellId < 0)
continue;
641 if(lpt().c_level(lptCellId) < lpt().maxRefinementLevel())
continue;
642 ASSERT(m_lptlbInterpolation,
"");
645 if(!lpt().c_isLeafCell(lptCellId)) {
646 ASSERT(m_lptlbInterpolation,
"");
649 const MInt noSurf = 1;
654 ASSERT(noSurf == 1,
"Only for single bndry-surfaces!");
657 std::array<MFloat, nDim> surfaceN;
658 std::array<MFloat, nDim> surfaceV;
659 std::array<MFloat, nDim + 1> bndryData;
809 lpt().addBndryCell(lptCellId, &bndryData[0], &surfaceN[0], surfaceC, &surfaceV[0]);
816template <MInt nDim, MInt nDist,
class SysEqn>
820 lpt().forceTimeStep( conversionLbLpt.time);
827template <MInt nDim, MInt nDist,
class SysEqn>
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;
837 lpt().a_isValidCell(lptCellId) =
true;
void preCouple(MInt) override
Coupling before each solver.
LPT< nDim > & lpt() const override
LbLpt(const MInt couplingId, LPT< nDim > *particle, LbSolver *lb)
void checkProperties() override
Check coupler properties for validity.
void initParticleVelocity()
Sets the initial particle velocity based on the flow field velocity in that cell. NOTE: This can not ...
void postCouple(MInt) override
Coupling after each solver.
void transferCellStatus()
set the isValid status for LPT cells based on the FV-solver cell properties
void transferFlowField()
Transfer the momentum source (forcing) from LPT to LB.
void updateLbSolver()
Transfer all relevant data from LPT to LB solver.
void transferTimeStep()
transfer/enforce Fv timeStep onto LPT solver
void init() override
Init coupling class.
void finalizeBalance(const MInt) override
postCouple: exchange source terms after the LPT timeStep
void finalizeCouplerInit() override
Finalize coupler initialization, coupler is ready after this.
void calculateGridBoundaries()
calculate Boundaries of box-shaped Grid for calculation of boundaryCellData
void updateLPTBndry()
Transfer all relevant bndryCell-data from LB to LPT.
This class is a ScratchSpace.
T * getPointer() const
Deprecated: use begin() instead!
void mTerm(const MInt errorCode, const MString &location, const MString &message)
constexpr Real POW3(const Real x)
constexpr Real POW2(const Real x)
constexpr T mMin(const T &x, const T &y)
constexpr T mMax(const T &x, const T &y)
std::basic_string< char > MString
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