23template <MInt a, MInt b>
25 std::vector<MFloat>& weight,
MFloat*
const gradientResult) {
26 std::vector<MInt>* nghbrL =
nullptr;
27 std::vector<MInt> tmp;
28 if(cellId == m_cellId) {
29 getNghbrList(m_neighborList, cellId);
30 nghbrL = &m_neighborList;
32 getNghbrList(tmp, cellId);
38 if(s_interpolationOrder > 0 || s_backPtr->m_couplingRedist) {
40 const auto noNghbr =
static_cast<MUint>(nghbrL->size());
46 if(noNghbr > 0 && (s_interpolationMethod > 0 || noNghbr != weight.size())) {
49 for(
MUint n = 0; n < noNghbr; n++) {
51 if(s_interpolationMethod > 0) {
52 for(
MInt i = 0; i < nDim; i++) {
53 const MFloat coord = s_backPtr->a_coordinate(nghbrL->at(n), i);
54 dx +=
POW2(coord - x[i]) + MFloatEps;
58 switch(s_interpolationMethod) {
61 weight.push_back(1.0);
65 weight.push_back(1.0 / dx);
69 const MFloat cellLength = s_backPtr->c_cellLengthAtLevel(s_backPtr->c_level(m_cellId));
71 MFloat distFactorImp = s_distFactorImp;
72 if(s_backPtr->m_engineSetup && s_backPtr->a_coordinate(m_cellId, 1) > 0.05) {
75 weight.push_back(exp(-distFactorImp * dx /
POW2(cellLength)));
79 TERMM(-1,
"Invalid interpolation method.");
81 sumImp += weight.back();
82 ASSERT(!std::isnan(weight.back()),
"ERROR: Weight is NaN with dx = " + std::to_string(dx) +
"!");
86 for(
MUint n = 0; n < noNghbr; n++) {
87 weight.at(n) /= sumImp;
95 if(
b > s_backPtr->PV.noVars()) {
99 switch(s_interpolationOrder) {
102 for(
MInt i =
a; i < c; i++) {
103 result[i] = s_backPtr->a_fluidVariable(cellId, i);
105 if(
b > s_backPtr->PV.noVars()) {
106 result[c] = s_backPtr->a_fluidSpecies(cellId);
112 for(
auto nghbrId : *nghbrL) {
113 for(
MInt i =
a; i < c; i++) {
114 result[i] += weight[n] * s_backPtr->a_fluidVariable(nghbrId, i);
116 if(
b > s_backPtr->PV.noVars()) {
117 result[c] += weight[n] * s_backPtr->a_fluidSpecies(nghbrId);
128 if(
b > s_backPtr->PV.noVars())
mTerm(1, AT_,
"Not implemented yet!");
130 std::array<MFloat, b + nDim * nDim> tempResults;
131 s_backPtr->template interpolateVariablesLS<a, b, true>(cellId, x, tempResults.data());
132 for(
MInt i =
a; i < c; i++) {
133 result[i -
a] = tempResults[i];
135 for(
MInt i = 0; i < nDim * nDim; i++) {
136 gradientResult[i] = tempResults[c + i];
139 s_backPtr->template interpolateVariablesLS<a, b>(cellId, x, result);
143 TERMM(-1,
"Invalid interpolation order.");
149 MFloat*
const result, std::vector<MFloat>& weight,
150 MFloat*
const gradientResult);
152 MFloat*
const result, std::vector<MFloat>& weight,
153 MFloat*
const gradientResult);
155 MFloat*
const result, std::vector<MFloat>& weight,
156 MFloat*
const gradientResult);
158 MFloat*
const result, std::vector<MFloat>& weight,
159 MFloat*
const gradientResult);
161 MFloat*
const result, std::vector<MFloat>& weight,
162 MFloat*
const gradientResult);
164 MFloat*
const result, std::vector<MFloat>& weight,
165 MFloat*
const gradientResult);
167 MFloat*
const result, std::vector<MFloat>& weight,
168 MFloat*
const gradientResult);
170 MFloat*
const result, std::vector<MFloat>& weight,
171 MFloat*
const gradientResult);
173 MFloat*
const result, std::vector<MFloat>& weight,
174 MFloat*
const gradientResult);
176 MFloat*
const result, std::vector<MFloat>& weight,
177 MFloat*
const gradientResult);
184 ASSERT(cellId >= 0,
"Invalid cellId!");
186 static const MInt noOfRedistLayers = (s_backPtr->m_noRedistLayer > 0) ? s_backPtr->m_noRedistLayer : 2;
188 MUint additionalLayers = 0;
190 if(s_backPtr->a_volumeFraction(m_cellId) > 0.75) {
193 additionalLayers = 1;
194 }
else if(!m_neighborList.empty() && m_neighborList[0] == cellId && !s_backPtr->a_isBndryCell(cellId)) {
204 if(s_backPtr->m_cellToNghbrHood.count(cellId) > 0
205 && s_backPtr->m_cellToNghbrHood[cellId].size() >= 50 * additionalLayers) {
207 neighborList = s_backPtr->m_cellToNghbrHood[cellId];
209 if(s_backPtr->m_cellToNghbrHood.count(cellId) > 0 && additionalLayers > 0) {
211 s_backPtr->m_cellToNghbrHood.erase(cellId);
213 neighborList.clear();
216 std::vector<MInt> neighborListGrid;
217 s_backPtr->grid().findNeighborHood(cellId, noOfRedistLayers + additionalLayers, neighborListGrid);
218 for(
MInt i = 0; i < (signed)neighborListGrid.size(); i++) {
219 if(s_backPtr->a_isValidCell(neighborListGrid[i])) {
220 neighborList.push_back(neighborListGrid[i]);
223 s_backPtr->m_cellToNghbrHood.emplace(make_pair(cellId, neighborList));
237 if(oldPosition !=
nullptr
238 && std::abs(m_position[0] - oldPosition[0]) + std::abs(m_position[1] - oldPosition[1])
239 + std::abs(m_position[2] - oldPosition[2])
244 if(m_cellId != -1) m_cellId = s_backPtr->grid().findContainingLeafCell(m_position.data(), m_cellId,
true);
246 if(allowHaloNonLeaf && m_cellId < 0) {
247 mTerm(1, AT_,
"Invalid cell during injection! Send not possible, broadcast required!");
250 if(m_cellId > 0 && !s_backPtr->c_isLeafCell(m_cellId)) {
251 if(!allowHaloNonLeaf) {
261 auto partWasHalo = wasSend();
263 if(m_cellId < 0 || (!partWasHalo && !s_backPtr->a_isValidCell(m_cellId))) {
264 toBeDeleted() =
true;
265 toBeRespawn() =
true;
271 const MBool origCellIsHaloCell = s_backPtr->a_isHalo(m_cellId);
272 const MBool origCellIsPeriodicHaloCell = s_backPtr->grid().isPeriodic(m_cellId);
277 if(origCellIsHaloCell) {
283 if(origCellIsPeriodicHaloCell) {
289 isWindow() = s_backPtr->a_isWindow(m_cellId);
305 if(s_backPtr->noDomains() > 1) {
306 if(s_backPtr->a_isHalo(m_cellId)) {
309 }
else if(s_backPtr->a_isWindow(m_cellId)) {
321 MLong debugPartId = -1;
324 const MFloat dt = s_backPtr->m_timeStep - m_creationTime;
326 const MInt bndId = s_backPtr->a_bndryCellId(m_cellId) > -1 ? s_backPtr->a_bndryCellId(m_cellId)
327 : s_backPtr->a_bndryCellId(m_oldCellId);
329 if(bndId < 0)
return;
331 const MInt lastValidCellId =
332 s_backPtr->a_isValidCell(m_cellId) ? m_cellId : s_backPtr->a_isValidCell(m_oldCellId) ? m_oldCellId : -1;
334 const MFloat radius = effectiveWallCollisionRadius();
336 std::array<MFloat, nDim> bodyVel{};
338 for(
MInt i = 0; i < nDim; i++) {
339 nBodyVel += s_backPtr->m_bndryCells->a[bndId].m_srfcs[0]->m_velocity[i]
340 * s_backPtr->m_bndryCells->a[bndId].m_srfcs[0]->m_normal[i];
343 for(
MInt i = 0; i < nDim; i++) {
344 bodyVel[i] = s_backPtr->m_bndryCells->a[bndId].m_srfcs[0]->m_velocity[i];
347 for(
MInt i = 0; i < nDim; i++) {
356 ASSERT(s_backPtr->m_bndryCells->a[bndId].m_noSrfcs == 1,
"Not implemented for multiple surfaces yet!");
358 std::array<MFloat, nDim> deltaX{};
359 for(
MInt i = 0; i < nDim; i++) {
360 deltaX[i] = m_position[i] - m_oldPos[i];
361 nx0 += s_backPtr->m_bndryCells->a[bndId].m_srfcs[0]->m_normal[i]
362 * s_backPtr->m_bndryCells->a[bndId].m_srfcs[0]->m_coordinates[i];
363 na += s_backPtr->m_bndryCells->a[bndId].m_srfcs[0]->m_normal[i] * m_oldPos[i];
364 nb += s_backPtr->m_bndryCells->a[bndId].m_srfcs[0]->m_normal[i] * deltaX[i];
369 MFloat lambda = (nx0 - na + radius) / nb;
376 if(lambda > 1.0 || nb > 0.0) {
380 const MFloat calculatedLambda = lambda;
382 if(lambda < -1.0) lambda = -1.0;
385 std::array<MFloat, nDim> oldC{};
386 for(
MInt i = 0; i < nDim; i++) {
387 oldC[i] = m_oldPos[i] + lambda * deltaX[i];
391 std::array<MFloat, nDim> usedVel{};
393 for(
MInt i = 0; i < nDim; i++) {
394 usedVel[i] = deltaX[i] / dt;
395 velMag +=
POW2(usedVel[i]);
397 velMag = sqrt(velMag);
400 if(m_partId == debugPartId) {
402 std::cerr <<
"Large velocity!" << velMag <<
" " << m_partId <<
" " << m_position[0] <<
" " << m_position[1] <<
" "
403 << m_position[2] <<
" " << m_velocity[0] <<
" " << m_velocity[1] <<
" " << m_velocity[2] <<
" "
404 << radius << std::endl;
411 std::array<MFloat, nDim> n{};
412 std::array<MFloat, nDim> u{};
413 std::array<MFloat, nDim> v{};
414 for(
MInt i = 0; i < nDim; i++) {
415 n[i] = s_backPtr->m_bndryCells->a[bndId].m_srfcs[0]->m_normal[i];
416 u[i] = s_backPtr->m_bndryCells->a[bndId].m_srfcs[0]->m_planeCoordinates[1][i]
417 - s_backPtr->m_bndryCells->a[bndId].m_srfcs[0]->m_planeCoordinates[0][i];
418 v[i] = s_backPtr->m_bndryCells->a[bndId].m_srfcs[0]->m_planeCoordinates[2][i]
419 - s_backPtr->m_bndryCells->a[bndId].m_srfcs[0]->m_planeCoordinates[0][i];
425 MFloat dotProductUV = std::inner_product(u.begin(), u.end(), v.begin(), 0.0);
426 for(
MInt i = 0; i < nDim; ++i) {
427 v[i] -= dotProductUV * u[i];
433 std::array<std::array<MFloat, nDim>, nDim> bndryBasis{};
435 for(
MInt i = 0; i < nDim; i++) {
436 bndryBasis[i][0] = n[i];
437 bndryBasis[i][1] = u[i];
438 bndryBasis[i][2] = v[i];
439 for(
MInt j = 0; j < nDim; j++) {
440 inverse(i, j) = bndryBasis[i][j];
447 if(m_partId == debugPartId) {
448 std::cerr <<
"Basis: " << std::endl;
449 std::cerr <<
" " << bndryBasis[0][0] <<
" " << bndryBasis[0][1] <<
" " << bndryBasis[0][2] << std::endl;
450 std::cerr <<
" " << bndryBasis[1][0] <<
" " << bndryBasis[1][1] <<
" " << bndryBasis[1][2] << std::endl;
451 std::cerr <<
" " << bndryBasis[2][0] <<
" " << bndryBasis[2][1] <<
" " << bndryBasis[2][2] << std::endl;
453 std::cerr <<
"Invert: " << std::endl;
454 std::cerr <<
" " << inverse(0, 0) <<
" " << inverse(0, 1) <<
" " << inverse(0, 2) << std::endl;
455 std::cerr <<
" " << inverse(1, 0) <<
" " << inverse(1, 1) <<
" " << inverse(1, 2) << std::endl;
456 std::cerr <<
" " << inverse(2, 0) <<
" " << inverse(2, 1) <<
" " << inverse(2, 2) << std::endl;
458 std::array<MFloat, nDim> a1{};
459 std::array<MFloat, nDim> a2{};
460 std::array<MFloat, nDim> a3{};
462 for(
MInt i = 0; i < nDim; i++) {
463 a1[i] = inverse(i, 0);
464 a2[i] = inverse(i, 1);
465 a3[i] = inverse(i, 2);
480 for(
MInt i = 0; i < nDim; i++) {
481 inverse2(i, 0) = a1[i];
482 inverse2(i, 1) = a2[i];
483 inverse2(i, 2) = a3[i];
486 std::cerr <<
"Invert2:" << std::endl;
487 std::cerr <<
" " << inverse2(0, 0) <<
" " << inverse2(0, 1) <<
" " << inverse2(0, 2) << std::endl;
488 std::cerr <<
" " << inverse2(1, 0) <<
" " << inverse2(1, 1) <<
" " << inverse2(1, 2) << std::endl;
489 std::cerr <<
" " << inverse2(2, 0) <<
" " << inverse2(2, 1) <<
" " << inverse2(2, 2) << std::endl;
493 std::cerr <<
"Invert3:" << std::endl;
494 std::cerr <<
" " << inverse2(0, 0) <<
" " << inverse2(0, 1) <<
" " << inverse2(0, 2) << std::endl;
495 std::cerr <<
" " << inverse2(1, 0) <<
" " << inverse2(1, 1) <<
" " << inverse2(1, 2) << std::endl;
496 std::cerr <<
" " << inverse2(2, 0) <<
" " << inverse2(2, 1) <<
" " << inverse2(2, 2) << std::endl;
501 std::array<MFloat, nDim> localVel{};
502 for(
MInt i = 0; i < nDim; i++) {
505 for(
MInt i = 0; i < nDim; i++) {
506 for(
MInt j = 0; j < nDim; j++) {
507 localVel[i] += inverse(i, j) * usedVel[j];
513 std::array<MFloat, nDim> localReboundVel{};
514 localReboundVel[0] = -localVel[0];
515 for(
MInt i = 1; i < nDim; i++) {
516 localReboundVel[i] = localVel[i];
520 if(m_partId == debugPartId) {
521 std::cerr <<
"RB " << localReboundVel[0] <<
" " << localReboundVel[1] <<
" " << localReboundVel[nDim - 1] <<
" "
522 << velMag << std::endl;
527 std::array<MFloat, nDim> reboundVel{};
528 for(
MInt i = 0; i < nDim; i++) {
530 for(
MInt j = 0; j < nDim; j++) {
531 reboundVel[i] += bndryBasis[i][j] * localReboundVel[j];
535 for(
MInt i = 0; i < nDim; i++) {
536 reboundVel[i] *= velMag;
538 for(
MInt i = 0; i < nDim; i++) {
539 m_oldVel[i] = reboundVel[i] + bodyVel[i];
540 m_velocity[i] = reboundVel[i] + bodyVel[i];
546 for(
MInt i = 0; i < nDim; i++) {
547 m_position[i] = oldC[i] + (1.0 - lambda) * dt * m_oldVel[i];
552 MFloat normalDistance = F0;
553 for(
MInt i = 0; i < nDim; i++) {
554 MFloat surfNormal = s_backPtr->m_bndryCells->a[bndId].m_srfcs[0]->m_normal[i];
555 MFloat surfCoord = s_backPtr->m_bndryCells->a[bndId].m_srfcs[0]->m_coordinates[i];
556 normalDistance += surfNormal * (m_oldPos[i] - surfCoord);
558 for(
MInt i = 0; i < nDim; i++) {
559 MFloat surfNormal = s_backPtr->m_bndryCells->a[bndId].m_srfcs[0]->m_normal[i];
560 m_position[i] = m_oldPos[i] + (radius - normalDistance) * surfNormal;
565 this->initProperties();
566 hadWallColl() =
true;
567 checkCellChange(m_oldPos.data());
571 if(lambda <= 0.0 && (m_cellId < 0 || m_cellId > s_backPtr->a_noCells() - 1 || !s_backPtr->a_isValidCell(m_cellId))) {
572 m_cellId = lastValidCellId;
573 for(
MInt i = 0; i < nDim; i++) {
574 m_position[i] = oldC[i];
576 this->initProperties();
577 hadWallColl() =
true;
578 checkCellChange(m_oldPos.data());
579 std::cerr <<
"Push back failed for particle " << m_partId <<
". Reducing it to surface."
580 <<
" newPos: " << m_cellId <<
" " << m_position[0] <<
" " << m_position[1] <<
" " << m_position[nDim - 1]
584 if(s_backPtr->a_isValidCell(m_oldCellId)
585 && (m_cellId < 0 || m_cellId > s_backPtr->a_noCells() - 1 || !s_backPtr->a_isValidCell(m_cellId))) {
586 m_cellId = lastValidCellId;
587 for(
MInt i = 0; i < nDim; i++) {
588 m_position[i] = m_oldPos[i];
590 this->initProperties();
591 hadWallColl() =
true;
592 checkCellChange(m_oldPos.data());
593 std::cerr <<
"Push back failed again for particle " << m_partId <<
". Resetting particle to old position."
594 <<
" newPos: " << m_cellId <<
" " << m_position[0] <<
" " << m_position[1] <<
" "
595 << m_position[nDim - 1] << std::endl;
597 if(m_cellId < 0 || m_cellId > s_backPtr->a_noCells() - 1 || !s_backPtr->a_isValidCell(m_cellId)) {
598 std::cerr <<
"Push back for particle " << m_partId <<
" kept failing. Particle could not be rescued."
607 for(
MInt i = 0; i < nDim; i++) {
609 m_oldPos[i] = oldC[i] + (lambda - 1.0) * dt * m_oldVel[i];
611 m_oldPos[i] = m_position[i] - dt * m_oldVel[i];
616 if(m_partId == debugPartId) {
617 std::cerr <<
"AC " << m_velocity[0] <<
" " << m_velocity[1] <<
" " << m_velocity[2] << std::endl;
621 if(m_cellId < 0 || m_cellId > s_backPtr->a_noCells() - 1 || !s_backPtr->a_isValidCell(m_cellId)) {
622 std::cerr <<
"Particle at invalid cell after collision " << m_cellId << std::endl;
623 if(m_cellId > 0 && m_cellId < s_backPtr->a_noCells()) {
624 std::cerr << s_backPtr->a_isValidCell(m_cellId) << std::endl;
626 std::cerr <<
" " << lastValidCellId <<
" " << s_backPtr->a_isValidCell(m_oldCellId) <<
" " << calculatedLambda
627 <<
" newPos " << m_position[0] <<
" " << m_position[1] <<
" " << m_position[nDim - 1] <<
" "
628 << s_backPtr->domainId() <<
" " << m_partId << std::endl;
629 std::cerr <<
"new-OldPos " << m_oldPos[0] <<
" " << m_oldPos[1] <<
" " << m_oldPos[nDim - 1] << std::endl;
630 std::cerr <<
"Surface " << s_backPtr->m_bndryCells->a[bndId].m_srfcs[0]->m_coordinates[0] <<
" "
631 << s_backPtr->m_bndryCells->a[bndId].m_srfcs[0]->m_coordinates[1] <<
" "
632 << s_backPtr->m_bndryCells->a[bndId].m_srfcs[0]->m_coordinates[nDim - 1] << std::endl;
633 std::cerr <<
"S-n " << s_backPtr->m_bndryCells->a[bndId].m_srfcs[0]->m_normal[0] <<
" "
634 << s_backPtr->m_bndryCells->a[bndId].m_srfcs[0]->m_normal[1] <<
" "
635 << s_backPtr->m_bndryCells->a[bndId].m_srfcs[0]->m_normal[nDim - 1] << std::endl;
636 std::cerr <<
"CollP " << oldC[0] <<
" " << oldC[1] <<
" " << oldC[nDim - 1] << std::endl;
637 std::cerr <<
" deltaX " << deltaX[0] <<
" " << deltaX[1] <<
" " << deltaX[nDim - 1] << std::endl;
638 std::cerr <<
"Vel1 " << usedVel[0] <<
" " << usedVel[1] <<
" " << usedVel[nDim - 1] << std::endl;
639 std::cerr <<
"Vel2 " << m_oldVel[0] <<
" " << m_oldVel[1] <<
" " << m_oldVel[nDim - 1] << std::endl;
640 std::cerr <<
"RbVel " << reboundVel[0] <<
" " << reboundVel[1] <<
" " << reboundVel[nDim - 1] << std::endl;
645 if(s_backPtr->a_isHalo(m_cellId)) {
657 const MFloat dt = s_backPtr->m_timeStep;
659 const MInt bndId = s_backPtr->a_bndryCellId(m_cellId) > -1 ? s_backPtr->a_bndryCellId(m_cellId)
660 : s_backPtr->a_bndryCellId(m_oldCellId);
662 if(bndId < 0)
return;
663 if(isInvalid())
return;
664 if(hadWallColl())
return;
668 for(
MInt i = 0; i < nDim; i++) {
669 bodyVelMag +=
POW2(s_backPtr->m_bndryCells->a[bndId].m_srfcs[0]->m_velocity[i]);
670 nBodyVel += s_backPtr->m_bndryCells->a[bndId].m_srfcs[0]->m_velocity[i]
671 * s_backPtr->m_bndryCells->a[bndId].m_srfcs[0]->m_normal[i];
673 bodyVelMag = sqrt(bodyVelMag);
677 if(bodyVelMag < MFloatEps || nBodyVel < 0)
return;
681 std::array<MFloat, nDim> deltaS{};
682 std::array<MFloat, nDim> vecSx{};
683 for(
MInt i = 0; i < nDim; i++) {
684 deltaS[i] = s_backPtr->m_bndryCells->a[bndId].m_srfcs[0]->m_velocity[i] * dt;
685 vecSx[i] = m_position[i] - s_backPtr->m_bndryCells->a[bndId].m_srfcs[0]->m_coordinates[i];
689 for(
MInt i = 0; i < nDim; i++) {
690 nx0 += s_backPtr->m_bndryCells->a[bndId].m_srfcs[0]->m_normal[i] * vecSx[i];
696 for(
MInt i = 0; i < nDim; i++) {
697 m_oldPos[i] = m_position[i];
698 m_position[i] = s_backPtr->m_bndryCells->a[bndId].m_srfcs[0]->m_coordinates[i] + deltaS[i];
699 m_velocity[i] = m_velocity[i] + s_backPtr->m_bndryCells->a[bndId].m_srfcs[0]->m_velocity[i];
700 m_oldVel[i] = m_oldVel[i] + s_backPtr->m_bndryCells->a[bndId].m_srfcs[0]->m_velocity[i];
704 this->initProperties();
705 hadWallColl() =
true;
706 checkCellChange(m_oldPos.data());
708 if(m_cellId < 0 || m_cellId > s_backPtr->a_noCells() - 1 || !s_backPtr->a_isValidCell(m_cellId)) {
709 std::cerr <<
"Particle at invalid cell after collision-2 " << m_cellId << std::endl;
714 if(s_backPtr->a_isHalo(m_cellId)) {
virtual void particleWallCollision()
particle-wall collision step
void interpolateAndCalcWeights(const MInt cellId, const MFloat *const x, MFloat *const result, std::vector< MFloat > &weight, MFloat *const gradientResult=nullptr)
void getNghbrList(std::vector< MInt > &, const MInt)
virtual void wallParticleCollision()
wall-particle collision step
void updateProperties(const MBool init=true)
Update particle properties.
void checkCellChange(const MFloat *oldPosition, const MBool allowHaloNonLeaf=false)
Checks whether position is within cell with number cellId if not, cellId is updated.
This class is a ScratchSpace.
void mTerm(const MInt errorCode, const MString &location, const MString &message)
constexpr Real POW2(const Real x)
MInt globalNoDomains()
Return global number of domains.
void invert(MFloat *A, const MInt m, const MInt n)
void normalize(std::array< T, N > &u)