19template <MInt nDim,
class SysEqn>
30template <MInt nDim,
class SysEqn>
35 RECORD_TIMER_STOP(timer(
"Total"));
40template <MInt nDim,
class SysEqn>
59 m_prolongationMethod = 0;
62 m_log <<
"Multilevel calculate gradients: " << m_prolongationMethod << std::endl;
75 m_correctCoarseBndry =
false;
79 fvSolver(0).setMultilevelPrimary();
81 initRestrictedCells();
87 resetMultiLevelVariables();
89 if(!fvSolver(0).m_adaptation || (
globalTimeStep > 0 && !fvSolver(0).m_levelSetMb)) {
90 resetSecondaryFlowVariables();
98template <MInt nDim,
class SysEqn>
105 if(m_correctCoarseBndry && !fvSolver(0).m_levelSetMb) {
107 correctCoarseBndryCells(solverId);
111 const auto nan = std::numeric_limits<MFloat>::quiet_NaN();
112 auto& fine = fvSolver(0);
113 for(
MInt cellId = 0; cellId < fine.a_noCells(); cellId++) {
114 if(fine.a_isInactive(cellId)) {
115 for(
MInt varId = 0; varId < fine.CV->noVariables; varId++) {
116 fine.a_variable(cellId, varId) = nan;
125template <MInt nDim,
class SysEqn>
127 if(solverId == fvSolver(
noSolvers() - 1).solverId()) {
130 m_restrictedCells.clear();
131 m_coarse2fine.clear();
132 m_fine2coarse.clear();
134 m_splitCellMapping.clear();
136 initRestrictedCells();
143 resetMultiLevelVariables();
145 resetSecondaryFlowVariables();
151template <MInt nDim,
class SysEqn>
154 if(solverId == fvSolver(0).solverId()) {
156 if(m_correctCoarseBndry && fvSolver(0).m_levelSetMb
157 && (fvSolver(0).m_reComputedBndry ||
globalTimeStep == fvSolver(0).m_restartTimeStep)) {
159 correctCoarseBndryCells(solver);
164 if(fvSolver(0).m_reComputedBndry ||
globalTimeStep == fvSolver(0).m_restartTimeStep) {
169template <MInt nDim,
class SysEqn>
175 MInt activeLevel = -1;
177 if(fvSolver(solverId).getSolverStatus()) {
178 activeLevel = solverId;
182 if(activeLevel == -1) {
183 TERMM(1,
"Multilevel postCouple(): no active solver/level found!");
188 restriction(activeLevel);
200template <MInt nDim,
class SysEqn>
204 startTimer(
"Restriction");
207 if(level < 0 || level >
noSolvers() - 2) {
209 "Bad restriction level argument. Level designates the level which will be restricted, "
210 "starting from 0 (finest level) to noSolvers() - 2 (next-to-coarsest level). Current value: "
214 const MInt fineLevel = level;
215 const MInt coarseLevel = level + 1;
216 auto& fine = fvSolver(fineLevel);
217 auto& coarse = fvSolver(coarseLevel);
220 startTimer(
"ComputeFineRHS");
223 stopTimer(
"ComputeFineRHS");
226 restrictData(fineLevel);
228 coarse.exchangeData(&coarse.a_variable(0, 0), coarse.CV->noVariables);
229 coarse.exchangeData(&coarse.a_oldVariable(0, 0), coarse.CV->noVariables);
232 startTimer(
"ComputeCoarseLhsBnd");
235 stopTimer(
"ComputeCoarseLhsBnd");
237 if(m_prolongationMethod == 2) {
239 startTimer(
"CalcGradientsRestriction");
240 coarse.LSReconstructCellCenterCons(0);
241 stopTimer(
"CalcGradientsRestriction");
251 computeCoarseLevelCorrection(coarseLevel);
255 storeRestrictedVariables(coarseLevel);
257 stopTimer(
"Restriction");
262template <MInt nDim,
class SysEqn>
266 auto& coarse = fvSolver(level);
267 const MInt noVars = coarse.CV->noVariables;
270 const MInt noInternalCells = coarse.grid().noInternalCells();
271 for(
MInt cellId = 0; cellId < noInternalCells; cellId++) {
272 for(
MInt varId = 0; varId < noVars; varId++) {
273 coarse.a_tau(cellId, varId) = 0.0;
280template <MInt nDim,
class SysEqn>
284 startTimer(
"RestrictData");
287 auto& fine = fvSolver(level);
288 auto& coarse = fvSolver(level + 1);
289 const MInt noVars = fine.CV->noVariables;
292 std::fill_n(&sumVolumes[0], fine.noInternalCells(), std::numeric_limits<MFloat>::quiet_NaN());
296 for(
MInt cellId = 0; cellId < coarse.noInternalCells(); cellId++) {
297 const MInt fineCellId = m_coarse2fine[level + 1][cellId];
298 sumVolumes[fineCellId] = coarse.a_cellVolume(cellId);
303 vector<MInt> childLessCells;
304 const MInt noRestrictedCells = m_restrictedCells[level].
size();
305 for(
MInt restrictedCellId = 0; restrictedCellId < noRestrictedCells; restrictedCellId++) {
306 const MInt cellId = m_restrictedCells[level][restrictedCellId];
309 for(
MInt varId = 0; varId < noVars; varId++) {
310 fine.a_variable(cellId, varId) = 0.0;
311 fine.a_oldVariable(cellId, varId) = 0.0;
312 if(fine.m_dualTimeStepping) {
313 fine.a_dt1Variable(cellId, varId) = 0.0;
314 fine.a_dt2Variable(cellId, varId) = 0.0;
316 fine.a_rightHandSide(cellId, varId) = 0.0;
317 fine.a_tau(cellId, varId) = 0.0;
318 if(fine.m_levelSetMb) {
319 fine.m_rhs0[cellId][varId] = 0.0;
323 sumVolumes[cellId] = 0;
327 for(
MInt childId = 0; childId <
IPOW2(nDim); childId++) {
329 const MInt child = fine.c_childId(cellId, childId);
333 if(fine.a_isInactive(child)) {
338 const MFloat childVolume = fine.a_cellVolume(child);
339 volume += childVolume;
340 sumVolumes[cellId] += childVolume;
343 for(
MInt varId = 0; varId < noVars; varId++) {
344 fine.a_variable(cellId, varId) += fine.a_variable(child, varId) * childVolume;
345 fine.a_oldVariable(cellId, varId) += fine.a_oldVariable(child, varId) * childVolume;
346 if(fine.m_dualTimeStepping) {
347 fine.a_dt1Variable(cellId, varId) += fine.a_dt1Variable(child, varId) * childVolume;
348 fine.a_dt2Variable(cellId, varId) += fine.a_dt2Variable(child, varId) * childVolume;
350 fine.a_rightHandSide(cellId, varId) += fine.a_rightHandSide(child, varId);
351 fine.a_tau(cellId, varId) += fine.a_tau(child, varId);
352 if(fine.m_levelSetMb) {
353 fine.m_rhs0[cellId][varId] += fine.m_rhs0[child][varId];
360 for(
MInt varId = 0; varId < noVars; varId++) {
361 fine.a_variable(cellId, varId) = fine.a_variable(cellId, varId) / volume;
362 fine.a_oldVariable(cellId, varId) = fine.a_oldVariable(cellId, varId) / volume;
363 if(fine.m_dualTimeStepping) {
364 fine.a_dt1Variable(cellId, varId) = fine.a_dt1Variable(cellId, varId) / volume;
365 fine.a_dt2Variable(cellId, varId) = fine.a_dt2Variable(cellId, varId) / volume;
369 ASSERT(volume > -MFloatEps,
"");
370 const MInt coarseCellId = m_fine2coarse[level][restrictedCellId];
371 if(coarseCellId > -1 && !coarse.a_isInactive(coarseCellId)) {
372 childLessCells.push_back(restrictedCellId);
378 ASSERT(childLessCells.empty(),
"Warning, not matching children have been found for a multi-level solver");
381 for(
MInt cellId = 0; cellId < coarse.noInternalCells(); cellId++) {
382 const MInt fineCellId = m_coarse2fine[level + 1][cellId];
383 for(
MInt varId = 0; varId < noVars; varId++) {
384 coarse.a_variable(cellId, varId) = fine.a_variable(fineCellId, varId);
385 coarse.a_oldVariable(cellId, varId) = fine.a_oldVariable(fineCellId, varId);
386 if(fine.m_dualTimeStepping) {
387 coarse.a_dt1Variable(cellId, varId) = fine.a_dt1Variable(fineCellId, varId);
388 coarse.a_dt2Variable(cellId, varId) = fine.a_dt2Variable(fineCellId, varId);
392 const MFloat volumeFactor = coarse.a_cellVolume(cellId) / sumVolumes[fineCellId];
393 coarse.a_rightHandSide(cellId, varId) =
394 volumeFactor * (fine.a_rightHandSide(fineCellId, varId) - fine.a_tau(fineCellId, varId));
395 coarse.a_restrictedRHS(cellId, varId) = coarse.a_rightHandSide(cellId, varId);
396 coarse.a_tau(cellId, varId) = volumeFactor * fine.a_tau(fineCellId, varId);
397 if(coarse.m_levelSetMb) {
398 coarse.m_rhs0[cellId][varId] = volumeFactor * (fine.m_rhs0[fineCellId][varId] - fine.a_tau(fineCellId, varId));
404 for(
MInt sc = 0; sc < coarse.a_noSplitCells(); sc++) {
405 MInt totalSplitId = 0;
406 for(
MInt scc = 0; scc < coarse.a_noSplitChilds(sc); scc++) {
407 const MInt splitChild = coarse.a_splitChildId(sc, scc);
408 const MInt finceChild = m_splitCellMapping[level + 1][totalSplitId++];
409 for(
MInt varId = 0; varId < noVars; varId++) {
410 coarse.a_variable(splitChild, varId) = fine.a_variable(finceChild, varId);
411 coarse.a_oldVariable(splitChild, varId) = fine.a_oldVariable(finceChild, varId);
412 if(fine.m_dualTimeStepping) {
413 coarse.a_dt1Variable(splitChild, varId) = fine.a_dt1Variable(finceChild, varId);
414 coarse.a_dt2Variable(splitChild, varId) = fine.a_dt2Variable(finceChild, varId);
417 const MFloat volumeFactor = coarse.a_cellVolume(splitChild) / sumVolumes[finceChild];
418 coarse.a_rightHandSide(splitChild, varId) =
419 volumeFactor * (fine.a_rightHandSide(finceChild, varId) - fine.a_tau(finceChild, varId));
420 coarse.a_restrictedRHS(splitChild, varId) = coarse.a_rightHandSide(splitChild, varId);
421 coarse.a_tau(splitChild, varId) = volumeFactor * fine.a_tau(finceChild, varId);
422 if(coarse.m_levelSetMb) {
423 coarse.m_rhs0[splitChild][varId] =
424 volumeFactor * (fine.m_rhs0[finceChild][varId] - fine.a_tau(finceChild, varId));
431 stopTimer(
"RestrictData");
436template <MInt nDim,
class SysEqn>
440 startTimer(
"ComputeCoarseCorrection");
443 auto& coarse = fvSolver(level);
447 for(
MInt cellId = 0; cellId < coarse.noInternalCells(); cellId++) {
448 for(
MInt varId = 0; varId < coarse.CV->noVariables; varId++) {
449 coarse.a_tau(cellId, varId) = coarse.a_rightHandSide(cellId, varId) - coarse.a_restrictedRHS(cellId, varId);
453 stopTimer(
"ComputeCoarseCorrection");
458template <MInt nDim,
class SysEqn>
462 startTimer(
"StoreRestrictedVars");
465 auto& coarse = fvSolver(level);
472 for(
MInt cellId = coarse.noInternalCells(); cellId < coarse.a_noCells(); cellId++) {
473 coarse.setConservativeVariables(cellId);
477 for(
MInt cellId = 0; cellId < coarse.a_noCells(); cellId++) {
478 for(
MInt varId = 0; varId < coarse.CV->noVariables; varId++) {
479 ASSERT(!std::isnan(coarse.a_variable(cellId, varId)),
480 "Restricted variables of cellId " + std::to_string(cellId) +
" of domainId "
481 + std::to_string(coarse.domainId()) +
"are nan");
482 coarse.a_restrictedVar(cellId, varId) = coarse.a_variable(cellId, varId);
486 stopTimer(
"StoreRestrictedVars");
491template <MInt nDim,
class SysEqn>
495 startTimer(
"Prolongation");
498 auto& coarse =
static_cast<SolverType&
>(fvSolver(level));
499 auto& fine =
static_cast<SolverType&
>(fvSolver(level - 1));
502 if(m_prolongationMethod == 2) {
504 startTimer(
"StoreGradients");
505 const MInt noCells = coarse.noInternalCells();
506 const MInt noVars = coarse.CV->noVariables;
508 for(
MInt cellId = 0; cellId < noCells; cellId++) {
509 for(
MInt varId = 0; varId < noVars; varId++) {
510 for(
MInt i = 0; i < nDim; i++) {
511 slopes[cellId * noVars * nDim + varId * nDim + i] = coarse.a_storedSlope(cellId, varId, i);
515 stopTimer(
"StoreGradients");
518 startTimer(
"CalcGradientsProlongation");
519 coarse.LSReconstructCellCenterCons(0);
520 stopTimer(
"CalcGradientsProlongation");
523 startTimer(
"CalcGradientDelta");
524 for(
MInt cellId = 0; cellId < noCells; cellId++) {
525 for(
MInt varId = 0; varId < noVars; varId++) {
526 for(
MInt i = 0; i < nDim; i++) {
527 coarse.a_storedSlope(cellId, varId, i) -= slopes[cellId * noVars * nDim + varId * nDim + i];
531 stopTimer(
"CalcGradientDelta");
537 startTimer(
"FineLhsBnd");
538 fine.exchangeData(&fine.a_variable(0, 0), fine.CV->noVariables);
542 stopTimer(
"FineLhsBnd");
544 stopTimer(
"Prolongation");
549template <MInt nDim,
class SysEqn>
553 startTimer(
"ProlongData");
556 const MInt coarseLevel = level;
557 const MInt fineLevel = level - 1;
558 auto& coarse = fvSolver(coarseLevel);
559 auto& fine = fvSolver(fineLevel);
560 const MInt noVars = coarse.CV->noVariables;
561 const MInt noInternalCells = coarse.noInternalCells();
565 for(
MInt cellId = 0; cellId < coarse.a_noCells(); cellId++) {
566 if(cellId < coarse.c_noCells() && !coarse.c_isLeafCell(cellId)) {
569 for(
MInt varId = 0; varId < noVars; varId++) {
570 coarse.a_variable(cellId, varId) -= coarse.a_restrictedVar(cellId, varId);
576 const MInt noRestrictedCells = m_restrictedCells[fineLevel].size();
577 for(
MInt restrictedCellId = 0; restrictedCellId < noRestrictedCells; restrictedCellId++) {
578 const MInt cellId = m_restrictedCells[fineLevel][restrictedCellId];
579 for(
MInt varId = 0; varId < noVars; varId++) {
580 fine.a_variable(cellId, varId) = 0.0;
585 for(
MInt cellId = 0; cellId < noInternalCells; cellId++) {
586 const MInt fineCellId = m_coarse2fine[coarseLevel][cellId];
587 switch(m_prolongationMethod) {
590 for(
MInt varId = 0; varId < noVars; varId++) {
591 fine.a_variable(fineCellId, varId) += coarse.a_variable(cellId, varId);
596 for(
MInt varId = 0; varId < noVars; varId++) {
597 fine.a_variable(fineCellId, varId) += coarse.a_variable(cellId, varId);
598 for(
MInt i = 0; i < nDim; i++) {
599 fine.a_storedSlope(fineCellId, varId, i) = coarse.a_storedSlope(cellId, varId, i);
605 mTerm(1, AT_,
"Unknown prolongation method");
611 return static_cast<MFloat>(coarse.a_variable(cellId, varId));
615 return static_cast<MFloat>(coarse.a_coordinate(cellId,
id));
620 for(
MInt restrictedId = 0; restrictedId < noRestrictedCells; restrictedId++) {
621 const MInt cellId = m_restrictedCells[fineLevel][restrictedId];
622 const MInt coarseCellId = m_fine2coarse[fineLevel][restrictedId];
625 for(
MInt childId = 0; childId <
IPOW2(nDim); childId++) {
627 const MInt child = fine.c_childId(cellId, childId);
631 if(fine.a_isInactive(child)) {
635 switch(m_prolongationMethod) {
637 for(
MInt varId = 0; varId < noVars; varId++) {
638 fine.a_variable(child, varId) += fine.a_variable(cellId, varId);
643 MInt interpolationCells[8] = {-1, -1, -1, -1, -1, -1, -1, -1};
645 for(
MInt i = 0; i < nDim; i++) {
646 point[i] = fine.a_coordinate(child, i);
648 if(!fine.a_isBndryCell(child)) {
652 MBool backup = coarse.m_deleteNeighbour;
653 coarse.m_deleteNeighbour =
false;
654 std::function<
MBool(
const MInt,
const MInt)> alwaysTrue = [&](
const MInt,
const MInt) {
return true; };
656 const MInt position =
657 coarse.setUpInterpolationStencil(coarseCellId, interpolationCells, point, alwaysTrue,
false);
658 coarse.m_deleteNeighbour = backup;
660 ASSERT(position > -1,
"Return value of setUpInterpolationStencil is > -1");
666 for(
MInt id = 0;
id <
IPOW2(nDim);
id++) {
667 const MInt interpolationCell = interpolationCells[
id];
668 if(interpolationCell < 0) {
669 mTerm(1, AT_,
"Incorrect stencil!");
672 if(coarse.a_isInactive(interpolationCell)) {
673 ASSERT(coarse.a_isBndryCell(coarseCellId),
"");
674 const MInt bndryId = coarse.a_bndryId(coarseCellId);
675 const MInt ghostCellId = coarse.a_bndryGhostCellId(bndryId, 0);
676 if(ghostCellId > -1) {
678 interpolationCells[
id] = ghostCellId;
680 }
else if(coarse.a_cellVolume(interpolationCell)
681 / coarse.c_cellVolumeAtLevel(coarse.a_level(interpolationCell))
682 < coarse.m_fvBndryCnd->m_volumeLimitWall) {
683 const MInt bndryId = coarse.a_bndryId(interpolationCell);
684 const MInt ghostCellId = coarse.a_bndryGhostCellId(bndryId, 0);
685 if(ghostCellId > -1) {
686 interpolationCells[
id] = ghostCellId;
693 for(
MInt varId = 0; varId < noVars; varId++) {
694 fine.a_variable(child, varId) +=
695 coarse.leastSquaresInterpolation(&interpolationCells[0], &point[0], varId, consVar, coordinate);
699 const MInt position = coarse.setUpBndryInterpolationStencil(coarseCellId, interpolationCells, point);
701 for(
MInt id = 0;
id <
IPOW2(nDim);
id++) {
702 const MInt intCellId = interpolationCells[
id];
704 cerr << position <<
" " << coarseCellId <<
" " << coarse.domainId() << endl;
705 mTerm(1, AT_,
"Incorrect stencil at bndry!");
707 ASSERT(!coarse.a_isInactive(intCellId),
"");
711 ASSERT(position ==
IPOW2(nDim),
"");
712 for(
MInt varId = 0; varId < noVars; varId++) {
713 fine.a_variable(child, varId) +=
714 coarse.leastSquaresInterpolation(&interpolationCells[0], &point[0], varId, consVar, coordinate);
721 array<MFloat, nDim> dx{};
722 for(
MInt i = 0; i < nDim; i++) {
723 dx.at(i) = fine.a_coordinate(child, i) - fine.a_coordinate(cellId, i);
725 for(
MInt varId = 0; varId < noVars; varId++) {
726 fine.a_variable(child, varId) += fine.a_variable(cellId, varId);
727 for(
MInt i = 0; i < nDim; i++) {
728 fine.a_variable(child, varId) += fine.a_storedSlope(cellId, varId, i) * dx.at(i);
734 mTerm(1, AT_,
"Unknown prolongation method");
740 stopTimer(
"ProlongData");
745template <MInt nDim,
class SysEqn>
750 for(
MInt solverId = 0; solverId <
noSolvers() - 1; solverId++) {
751 auto& fineGrid = fvSolver(solverId).grid();
752 const MInt noInternalCells = fineGrid.noInternalCells();
753 const MInt restrictedLevel = fineGrid.maxLevel() - 1;
756 MInt noRestrictedCells = 0;
758 for(
MInt i = 0; i < noInternalCells; i++) {
759 if(fineGrid.tree().level(i) == restrictedLevel && fineGrid.tree().hasChildren(i)) {
760 restrictedCells[noRestrictedCells] = i;
766 m_restrictedCells[solverId].resize(noRestrictedCells);
767 copy_n(restrictedCells.
data(), noRestrictedCells, m_restrictedCells[solverId].data());
773template <MInt nDim,
class SysEqn>
779 auto& fineGrid = fvSolver(solverId - 1).grid();
780 auto& coarseGrid = fvSolver(solverId).grid();
781 const MInt noInternalCells = coarseGrid.noInternalCells();
782 m_coarse2fine[solverId].resize(noInternalCells);
783 for(
MInt i = 0; i < noInternalCells; i++) {
784 m_coarse2fine[solverId][i] = fineGrid.tree().grid2solver(coarseGrid.tree().solver2grid(i));
790 for(
MInt solverId = 0; solverId <
noSolvers() - 1; solverId++) {
791 auto& fineGrid = fvSolver(solverId).grid();
792 auto& coarseGrid = fvSolver(solverId + 1).grid();
793 const MInt noRestrictedCells = m_restrictedCells[solverId].size();
794 m_fine2coarse[solverId].resize(noRestrictedCells);
795 for(
MInt i = 0; i < noRestrictedCells; i++) {
796 const MInt fineCellId = m_restrictedCells[solverId][i];
797 m_fine2coarse[solverId][i] = coarseGrid.tree().grid2solver(fineGrid.tree().solver2grid(fineCellId));
804template <MInt nDim,
class SysEqn>
808 m_splitCellMapping.clear();
811 auto& fine = fvSolver(solverId - 1);
812 auto& coarse = fvSolver(solverId);
813 if(coarse.m_totalnosplitchilds == 0) {
816 m_splitCellMapping[solverId].resize(coarse.m_totalnosplitchilds);
817 MInt totalSplitId = 0;
818 for(
MInt sc = 0; sc < coarse.a_noSplitCells(); sc++) {
819 const MInt splitCell = coarse.a_splitCellId(sc);
820 const MInt fineCell = m_coarse2fine[solverId][splitCell];
821 for(
MInt scc = 0; scc < coarse.a_noSplitChilds(sc); scc++) {
822 const MInt splitChild = coarse.a_splitChildId(sc, scc);
823 std::map<MFloat, MInt> distances;
825 for(
MInt childId = 0; childId <
IPOW2(nDim); childId++) {
826 const MInt child = fine.c_childId(fineCell, childId);
831 if(fine.a_isSplitCell(fineCell)) {
832 for(
MInt fsc = 0; fsc < fine.a_noSplitCells(); fsc++) {
833 const MInt fineSplitCell = fine.a_splitCellId(fsc);
834 if(fineSplitCell == fineCell) {
835 for(
MInt fscc = 0; fscc < fine.a_noSplitChilds(fsc); fscc++) {
837 const MInt fineSplitChild = fine.a_splitChildId(fsc, fscc);
838 for(
MInt i = 0; i < nDim; i++) {
839 dist +=
POW2(coarse.a_coordinate(splitChild, i) - fine.a_coordinate(fineSplitChild, i));
842 distances.insert(make_pair(
dist, splitChild));
848 if(fine.a_isInactive(child)) {
851 for(
MInt i = 0; i < nDim; i++) {
852 dist +=
POW2(coarse.a_coordinate(splitChild, i) - fine.a_coordinate(child, i));
855 distances.insert(make_pair(
dist, child));
858 if(distances.empty()) {
859 cerr <<
"Neighbor search necessary!" << distances.size() <<
" " << distances.begin()->second <<
" "
860 << coarse.a_isHalo(splitCell) << endl;
863 const MInt childId = distances.begin()->second;
864 m_splitCellMapping[solverId][totalSplitId++] = childId;
870template <MInt nDim,
class SysEqn>
875 std::vector<MInt> noLeafCells(
noSolvers(), 0);
877 const MInt noInternalCells = fvSolver(solverId).grid().noInternalCells();
878 for(
MInt i = 0; i < noInternalCells; i++) {
879 if(fvSolver(solverId).grid().tree().isLeafCell(i)) {
880 noLeafCells[solverId]++;
887 m_leafCells[solverId].resize(noLeafCells[solverId]);
888 const MInt noInternalCells = fvSolver(solverId).grid().noInternalCells();
890 for(
MInt i = 0; i < noInternalCells; i++) {
891 if(fvSolver(solverId).grid().tree().isLeafCell(i)) {
892 m_leafCells[solverId][index] = i;
900template <MInt nDim,
class SysEqn>
904 const auto nan = std::numeric_limits<MFloat>::quiet_NaN();
906 auto& current = fvSolver(solverId);
907 const MInt noVars = current.CV->noVariables;
908 const MInt noCells = current.a_noCells();
909 for(
MInt cellId = 0; cellId < noCells; cellId++) {
910 for(
MInt varId = 0; varId < noVars; varId++) {
911 current.a_tau(cellId, varId) = 0.0;
912 current.a_restrictedRHS(cellId, varId) = nan;
913 current.a_restrictedVar(cellId, varId) = nan;
914 for(
MInt i = 0; i < nDim; i++) {
915 current.a_storedSlope(cellId, varId, i) = nan;
924template <MInt nDim,
class SysEqn>
928 const auto nan = std::numeric_limits<MFloat>::quiet_NaN();
931 auto& current = fvSolver(solverId);
932 const MInt noVars = current.CV->noVariables;
933 const MInt noCells = current.noInternalCells();
934 for(
MInt cellId = 0; cellId < noCells; cellId++) {
935 for(
MInt varId = 0; varId < noVars; varId++) {
936 current.a_variable(cellId, varId) = nan;
937 current.a_rightHandSide(cellId, varId) = nan;
938 if(current.m_levelSetMb) {
939 current.m_rhs0[cellId][varId] = nan;
943 for(
MInt varId = 0; varId < noVars; varId++) {
944 current.a_pvariable(cellId, varId) = nan;
960template <MInt nDim,
class SysEqn>
964 auto& fine = fvSolver(solverId - 1);
965 auto& coarse = fvSolver(solverId);
968 cerr <<
"Correxting secondary bndry-cell volumes and centers " << endl;
971 const MInt noCoarseCells = coarse.a_noCells();
977 const auto nan = std::numeric_limits<MFloat>::quiet_NaN();
978 fill(bndryCoordinates.
begin(), bndryCoordinates.
end(), nan);
979 fill(cellCoordinates.
begin(), cellCoordinates.
end(), nan);
980 fill(srfcCoordinates.
begin(), srfcCoordinates.
end(), nan);
981 fill(volumes.
begin(), volumes.
end(), nan);
984 for(
MInt bndryId = 0; bndryId < coarse.m_bndryCells->size(); bndryId++) {
986 const MInt coarseCellId = coarse.m_bndryCells->a[bndryId].m_cellId;
987 ASSERT(coarseCellId > -1,
"");
988 if(!coarse.c_isLeafCell(coarseCellId)) {
992 if(coarse.a_isHalo(coarseCellId)) {
997 const MInt fineCellId = m_coarse2fine[solverId][coarseCellId];
1002 if(fine.grid().tree().hasChildren(fineCellId)) {
1003 const MInt noChildren = fine.grid().tree().noChildren(fineCellId);
1004 if(noChildren == 0) {
1010 MFloat bndryCellVolumes = 0;
1013 array<MFloat, nDim> bndryXyz{};
1014 array<MFloat, nDim> cellXyz{};
1015 array<MFloat, nDim> srfcXyz{};
1022 for(
MInt childId = 0; childId <
IPOW2(nDim); childId++) {
1023 const MInt childCellId = fine.c_childId(fineCellId, childId);
1024 if(childCellId == -1) {
1027 if(fine.a_isInactive(childCellId)) {
1031 ASSERT(fine.c_isLeafCell(childCellId),
"");
1033 const MInt bndryCellId = fine.a_bndryId(childCellId);
1034 if(bndryCellId > -1) {
1035 volume += fine.m_bndryCells->a[bndryCellId].m_volume;
1036 bndryCellVolumes += fine.m_bndryCells->a[bndryCellId].m_volume;
1038 for(
MInt i = 0; i < nDim; i++) {
1039 bndryXyz.at(i) += fine.a_coordinate(childCellId, i) * fine.m_bndryCells->a[bndryCellId].m_volume;
1043 srfcArea += fine.m_bndryCells->a[bndryCellId].m_srfcs[0]->m_area;
1045 for(
MInt i = 0; i < nDim; i++) {
1046 srfcXyz.at(i) += fine.m_bndryCells->a[bndryCellId].m_srfcs[0]->m_coordinates[i]
1047 * fine.m_bndryCells->a[bndryCellId].m_srfcs[0]->m_area;
1051 const MFloat childVolume = fine.c_cellVolumeAtLevel(fine.a_level(childCellId));
1052 volume += childVolume;
1053 for(
MInt i = 0; i < nDim; i++) {
1054 cellXyz.at(i) += fine.a_coordinate(childCellId, i) * childVolume;
1059 for(
MInt i = 0; i < nDim; i++) {
1060 cellXyz[i] += bndryXyz[i];
1061 cellXyz[i] = cellXyz[i] / volume;
1062 bndryXyz[i] = bndryXyz[i] / bndryCellVolumes;
1063 srfcXyz[i] = srfcXyz[i] / srfcArea;
1069 for(
MInt i = 0; i < nDim; i++) {
1070 coarse.m_bndryCells->a[bndryId].m_coordinates[i] += cellXyz[i] - coarse.a_coordinate(coarseCellId, i);
1071 coarse.a_coordinate(coarseCellId, i) = cellXyz[i];
1072 coarse.m_bndryCells->a[bndryId].m_srfcs[0]->m_coordinates[i] = srfcXyz[i];
1075 bndryCoordinates(coarseCellId, i) = coarse.m_bndryCells->a[bndryId].m_coordinates[i];
1076 cellCoordinates(coarseCellId, i) = cellXyz[i];
1077 srfcCoordinates(coarseCellId, i) = srfcXyz[i];
1081 coarse.m_bndryCells->a[bndryId].m_volume = volume;
1083 volumes(coarseCellId) = volume;
1088 coarse.exchangeData(&volumes(0, 0), 1);
1089 coarse.exchangeData(&bndryCoordinates(0, 0), nDim);
1090 coarse.exchangeData(&cellCoordinates(0, 0), nDim);
1091 coarse.exchangeData(&srfcCoordinates(0, 0), nDim);
1094 for(
MInt bndryId = 0; bndryId < coarse.m_bndryCells->size(); bndryId++) {
1095 const MInt coarseCellId = coarse.m_bndryCells->a[bndryId].m_cellId;
1097 if(coarseCellId < 0) {
1100 if(!coarse.a_isHalo(coarseCellId)) {
1103 if(coarse.a_level(coarseCellId) != coarse.maxLevel()) {
1107 for(
MInt i = 0; i < nDim; i++) {
1108 coarse.m_bndryCells->a[bndryId].m_coordinates[i] = bndryCoordinates(coarseCellId, i);
1109 coarse.a_coordinate(coarseCellId, i) = cellCoordinates(coarseCellId, i);
1110 coarse.m_bndryCells->a[bndryId].m_srfcs[0]->m_coordinates[i] = srfcCoordinates(coarseCellId, i);
1113 ASSERT(volumes(coarseCellId) > -MFloatEps,
"coarse multi-level solver has negative-cell volume after correction!");
1114 coarse.m_bndryCells->a[bndryId].m_volume = volumes(coarseCellId);
1117 coarse.computeCellVolumes();
1127template <MInt nDim,
class SysEqn>
1134 auto&
b = fvSolver(i);
1135 if(
b.m_fvBndryCnd->m_smallBndryCells->size() > 0) {
1136 TERMM(1,
"Old concept of merged cells not (yet) supported");
1138 if(!
b.m_fvBndryCnd->m_smallCutCells.empty()) {
1139 cerr <<
"Multilevel: small cells might not be handled properly yet, continue anyway..." << endl;
1145 TERMM(1,
"Multilevel computation does not make sense with less than two solvers");
1150 if(mode == 0 && fvSolver(0).m_adaptation &&
globalTimeStep == 0) {
1156 const MInt overallMaxLevel = fvSolver(0).grid().maxLevel();
1157 for(
MInt solverId = 1; solverId <
noSolvers(); solverId++) {
1158 if(fvSolver(solverId).grid().maxLevel() != overallMaxLevel - solverId) {
1160 "Maximum refinement level not reduced by one between solvers " + to_string(solverId - 1) +
" and "
1161 + to_string(solverId));
1163 if(fvSolver(solverId).m_levelSetMb != fvSolver(0).m_levelSetMb) {
1164 TERMM(1,
"Multilevel coupling of different fv-solver types not allowed yet!");
1170 for(
MInt solverId = 0; solverId <
noSolvers() - 1; solverId++) {
1171 const MInt noInternalCells = fvSolver(solverId).grid().noInternalCells();
1172 const MInt restrictedLevel = fvSolver(solverId).grid().maxLevel() - 1;
1174 for(
MInt i = 0; i < noInternalCells; i++) {
1177 if(fvSolver(solverId).grid().tree().level(i) == restrictedLevel
1178 || (fvSolver(solverId).grid().tree().level(i) < restrictedLevel
1179 && fvSolver(solverId).grid().tree().isLeafCell(i))) {
1181 if(fvSolver(solverId).grid().tree().solver2grid(i)
1182 == fvSolver(solverId + 1).grid().tree().solver2grid(m_leafCells[solverId + 1][count])) {
1186 "Mismatch between restricted cells of solver " + to_string(solverId) +
" and leaf cells of solver "
1187 + to_string(solverId + 1));
1193 if(count !=
static_cast<MInt>(m_leafCells[solverId + 1].size())) {
1194 TERMM(1,
"Number of restricted cells and number of leaf cells does not match");
1201 for(
MInt solverId = 0; solverId <
noSolvers() - 1; solverId++) {
1202 auto& fine = fvSolver(solverId);
1203 auto& coarse = fvSolver(solverId + 1);
1204 for(
MInt restrictedId = 0; restrictedId < (signed)m_restrictedCells[solverId].size(); restrictedId++) {
1205 const MInt fineCellId = m_restrictedCells[solverId][restrictedId];
1206 const MInt coarseCellId = m_fine2coarse[solverId][restrictedId];
1207 ASSERT(fineCellId == m_coarse2fine[solverId + 1][coarseCellId],
1208 "fineCellId is eqal to coarseCellId on the n+1 solver");
1209 ASSERT(fine.grid().tree().solver2grid(fineCellId) == coarse.grid().tree().solver2grid(coarseCellId),
1210 "solver2grid of the finecellId is equal to solver2grid of the coarseCellId ");
1211 ASSERT(fine.a_level(fineCellId) == coarse.a_level(coarseCellId) && fine.c_noChildren(fineCellId) > 0,
1212 "fineCellId is on the same level as coarseCellId and children exists");
1225template <MInt nDim,
class SysEqn>
1227 if(m_timers.count(name) == 0) {
1228 TERMM(1,
"Timer '" + name +
"' does not exist.");
1230 return m_timers.at(name);
1234template <MInt nDim,
class SysEqn>
1239 if(m_timers.count(name) > 0) {
1240 TERMM(1,
"Timer '" + name +
"' already exists.");
1244 m_timers[name] = -1;
1247 return m_timers[name];
1251template <MInt nDim,
class SysEqn>
1254 TERMM(1,
"Empty timer name");
1256 RECORD_TIMER_START(timer(name));
1261template <MInt nDim,
class SysEqn>
1264 TERMM(1,
"Empty timer name");
1266 RECORD_TIMER_STOP(timer(name));
1271template <MInt nDim,
class SysEqn>
1276 NEW_TIMER_GROUP_NOCREATE(m_timerGroup,
"CouplerFvMultilevel");
1277 NEW_TIMER_NOCREATE(createTimer(
"Total"),
"Total object lifetime", m_timerGroup);
1278 RECORD_TIMER_START(timer(
"Total"));
1281 NEW_SUB_TIMER_NOCREATE(createTimer(
"Init"),
"Initialization", timer(
"Total"));
1284 NEW_SUB_TIMER_NOCREATE(createTimer(
"Main"),
"Post couple", timer(
"Total"));
1285 NEW_SUB_TIMER_NOCREATE(createTimer(
"Restriction"),
"Restriction", timer(
"Main"));
1286 NEW_SUB_TIMER_NOCREATE(createTimer(
"Prolongation"),
"Prolongation", timer(
"Main"));
1287 NEW_SUB_TIMER_NOCREATE(createTimer(
"I/O"),
"I/O", timer(
"Main"));
1290 NEW_SUB_TIMER_NOCREATE(createTimer(
"ComputeFineRHS"),
"fine.rhs(),fine.rhsBnd()", timer(
"Restriction"));
1291 NEW_SUB_TIMER_NOCREATE(createTimer(
"RestrictData"),
"restrictData()", timer(
"Restriction"));
1292 NEW_SUB_TIMER_NOCREATE(createTimer(
"ComputeCoarseLhsBnd"),
"coarse.lhsBnd()", timer(
"Restriction"));
1293 NEW_SUB_TIMER_NOCREATE(
1294 createTimer(
"CalcGradientsRestriction"),
"coarse.LSReconstructCellCenterCons()", timer(
"Restriction"));
1295 NEW_SUB_TIMER_NOCREATE(
1296 createTimer(
"ComputeCoarseCorrection"),
"computeCoarseLevelCorrection()", timer(
"Restriction"));
1297 NEW_SUB_TIMER_NOCREATE(createTimer(
"StoreRestrictedVars"),
"storeRestrictedVariables()", timer(
"Restriction"));
1300 NEW_SUB_TIMER_NOCREATE(createTimer(
"StoreGradients"),
"store gradients", timer(
"Prolongation"));
1301 NEW_SUB_TIMER_NOCREATE(
1302 createTimer(
"CalcGradientsProlongation"),
"coarse.LSReconstructCellCenterCons()", timer(
"Prolongation"));
1303 NEW_SUB_TIMER_NOCREATE(createTimer(
"CalcGradientDelta"),
"calc gradient delta", timer(
"Prolongation"));
1304 NEW_SUB_TIMER_NOCREATE(createTimer(
"ProlongData"),
"prolongData()", timer(
"Prolongation"));
1305 NEW_SUB_TIMER_NOCREATE(createTimer(
"FineLhsBnd"),
"fine.lhsBnd()", timer(
"Prolongation"));
1310template <MInt nDim,
class SysEqn>
1319template <MInt nDim,
class SysEqn>
1324 for(
MInt solverId = 0; solverId <
noSolvers(); solverId++) {
1325 if(fvSolver(solverId).getSolverStatus()) {
1326 TERMM(1,
"Multilevel interpolation postCouple(): found active solver/level - all solvers should be inactive!");
1346template <MInt nDim,
class SysEqn>
1350 auto& fine = fvSolver(level);
1351 auto& coarse = fvSolver(level + 1);
1352 const MInt noVars = fine.CV->noVariables;
1354 for(
MInt cellId = 0; cellId < fine.noInternalCells(); cellId++) {
1355 for(
MInt varId = 0; varId < noVars; varId++) {
1357 fine.a_variable(cellId, varId) = 0.0;
1358 for(
MInt dim = 0; dim < nDim; dim++) {
1360 fine.a_storedSlope(cellId, varId, dim) = 0.0;
1365 for(
MInt cellId = 0; cellId < coarse.noInternalCells(); cellId++) {
1366 for(
MInt varId = 0; varId < noVars; varId++) {
1368 coarse.a_restrictedVar(cellId, varId) = 0.0;
1369 for(
MInt dim = 0; dim < nDim; dim++) {
1371 coarse.a_storedSlope(cellId, varId, dim) = 0.0;
static T getBasicProperty(const MString name, const MString &nameOfCallingFunction, const T *default_value, MInt pos=0)
void correctCoarseBndryCells(const MInt solverId)
MInt timer(const MString &name)
void initRestrictedCells()
for each solver that will be restricted (all except the coarsest), store restricted cells
void finalizeCouplerInit()
call after the initial adaptation when all cells are refined correctly
MBool stopTimer(const MString &name)
void postCouple(MInt) override
void initLeafCells()
store internal leaf cells for each solver except for finest solver, for which they are not needed
void restrictData(const MInt level)
Restrict the data (fine-coarse) on the given level.
void resetSecondaryFlowVariables()
for each solver except the finest, reset variables to NaN to ensure that only restricted information ...
void prolongation(const MInt level)
Prolong the solution on the given coarse level onto the next finer level.
void storeRestrictedVariables(const MInt level)
Store the restricted variables (required for the prolongation)
typename BaseFv::solverType SolverType
CouplerFvMultilevel(const MInt couplingId, std::vector< FvCartesianSolverXD< nDim, SysEqn > * > solvers)
void prolongData(const MInt level)
Prolong the data of a coarse level.
void finalizeAdaptation(MInt solverId)
call after the initial adaptation when all cells are refined correctly
void initSplitMapping()
for each coarse solver, store cell map of split-cells to next finer solver childs
void initMapping()
for each coarse solver, store cell map to next finer solver
MInt & createTimer(const MString &name)
void preCouple(MInt) override
void computeCoarseLevelCorrection(const MInt level)
Compute the coarse level correction tau.
void resetTau(const MInt level)
Reset the coarse level correction tau.
MBool startTimer(const MString &name)
void resetMultiLevelVariables()
for each solver, reset multilevel variables
void restriction(const MInt level)
Restrict the solution on the given fine level onto the next coarser level.
FV multilevel interpolation coupler to transfer solution data of a coarse grid onto a finer grid.
typename BaseCoupler::Base Base
void postCouple(MInt) override
Coupling routine to transfer coarse level restart data to the finest level/solver.
void reset(const MInt level)
Reset variables/slopes of a level/solver.
CouplerFvMultilevelInterpolation(const MInt couplingId, std::vector< FvCartesianSolverXD< nDim, SysEqn > * > solvers)
Constructor for multilevel interpolation coupler.
This class is a ScratchSpace.
void mTerm(const MInt errorCode, const MString &location, const MString &message)
constexpr Real POW2(const Real x)
constexpr MLong IPOW2(MInt x)
std::basic_string< char > MString
MFloat dist(const Point< DIM > &p, const Point< DIM > &q)