MAIA bb96820c
Multiphysics at AIA
Loading...
Searching...
No Matches
CouplerFvMultilevel< nDim, SysEqn > Class Template Reference

#include <couplerfvmultilevel.h>

Inheritance diagram for CouplerFvMultilevel< nDim, SysEqn >:
[legend]
Collaboration diagram for CouplerFvMultilevel< nDim, SysEqn >:
[legend]

Public Types

using Base = Coupling
 
using BaseFv = CouplingFv< nDim, SysEqn >
 
using SolverType = typename BaseFv::solverType
 
using Grid = CartesianGrid< nDim >
 
using GridProxy = typename SolverType::GridProxy
 
- Public Types inherited from CouplingFv< nDim, SysEqn >
using solverType = FvCartesianSolverXD< nDim, SysEqn >
 

Public Member Functions

 CouplerFvMultilevel (const MInt couplingId, std::vector< FvCartesianSolverXD< nDim, SysEqn > * > solvers)
 
 ~CouplerFvMultilevel ()
 
void init () override
 
void finalizeSubCoupleInit (MInt)
 
void finalizeCouplerInit ()
 call after the initial adaptation when all cells are refined correctly More...
 
void preCouple (MInt) override
 
void subCouple (MInt, MInt, std::vector< MBool > &) override
 
void postCouple (MInt) override
 
void cleanUp ()
 
void getDomainDecompositionInformation (std::vector< std::pair< MString, MInt > > &NotUsed(domainInfo)) override
 Return information on current domain decomposition (e.g. number of coupled cells/elements/...) More...
 
void finalizeAdaptation (MInt solverId)
 call after the initial adaptation when all cells are refined correctly More...
 
void readProperties () override
 
void checkProperties () override
 
void restriction (const MInt level)
 Restrict the solution on the given fine level onto the next coarser level. More...
 
void resetTau (const MInt level)
 Reset the coarse level correction tau. More...
 
void prolongation (const MInt level)
 Prolong the solution on the given coarse level onto the next finer level. More...
 
void sanityCheck ()
 
MBool startTimer (const MString &name)
 
MBool stopTimer (const MString &name)
 
solverTypefvSolver (const MInt solverId=0) const
 
MInt noSolvers () const
 
- Public Member Functions inherited from CouplingFv< nDim, SysEqn >
 CouplingFv (const MInt couplingId, std::vector< FvCartesianSolverXD< nDim, SysEqn > * > fvSolvers, const MInt noSolvers)
 
 CouplingFv (const MInt couplingId, Solver *solvers)
 
 ~CouplingFv () override=default
 
 CouplingFv (const CouplingFv &)=delete
 
CouplingFvoperator= (const CouplingFv &)=delete
 
- Public Member Functions inherited from Coupling
 Coupling (const MInt couplingId)
 
virtual ~Coupling ()=default
 
 Coupling (const Coupling &)=delete
 
Couplingoperator= (const Coupling &)=delete
 
MInt couplerId () const
 
virtual void init ()=0
 
virtual void finalizeSubCoupleInit (MInt solverId)=0
 
virtual void finalizeCouplerInit ()=0
 
virtual void preCouple (MInt recipeStep)=0
 
virtual void subCouple (MInt recipeStep, MInt solverId, std::vector< MBool > &solverCompleted)=0
 
virtual void postCouple (MInt recipeStep)=0
 
virtual void cleanUp ()=0
 
virtual void balancePre ()
 Load balancing. More...
 
virtual void balancePost ()
 
virtual void reinitAfterBalance ()
 
virtual void prepareAdaptation ()
 
virtual void postAdaptation ()
 
virtual void finalizeAdaptation (const MInt)
 
virtual void writeRestartFile (const MInt)
 
virtual MInt noCellDataDlb () const
 Methods to inquire coupler data during balancing. More...
 
virtual MInt cellDataTypeDlb (const MInt NotUsed(dataId)) const
 
virtual MInt cellDataSizeDlb (const MInt NotUsed(dataId), const MInt NotUsed(cellId))
 
virtual void getCellDataDlb (const MInt NotUsed(dataId), const MInt NotUsed(oldNoCells), const MInt *const NotUsed(bufferIdToCellId), MInt *const NotUsed(data))
 
virtual void getCellDataDlb (const MInt NotUsed(dataId), const MInt NotUsed(oldNoCells), const MInt *const NotUsed(bufferIdToCellId), MLong *const NotUsed(data))
 
virtual void getCellDataDlb (const MInt NotUsed(dataId), const MInt NotUsed(oldNoCells), const MInt *const NotUsed(bufferIdToCellId), MFloat *const NotUsed(data))
 
virtual void setCellDataDlb (const MInt NotUsed(dataId), const MInt *const NotUsed(data))
 
virtual void setCellDataDlb (const MInt NotUsed(dataId), const MLong *const NotUsed(data))
 
virtual void setCellDataDlb (const MInt NotUsed(dataId), const MFloat *const NotUsed(data))
 
virtual void finalizeBalance (const MInt)
 
virtual MInt noCouplingTimers (const MBool NotUsed(allTimings)) const
 Number of coupling timers. More...
 
virtual void getCouplingTimings (std::vector< std::pair< MString, MFloat > > &NotUsed(timings), const MBool NotUsed(allTimings))
 Return coupling timings. More...
 
virtual void getDomainDecompositionInformation (std::vector< std::pair< MString, MInt > > &NotUsed(domainInfo))
 Return information on current domain decomposition (e.g. number of coupled cells/elements/...) More...
 
void setDlbTimer (const MInt timerId)
 
void startLoadTimer (const MString &name) const
 Start the load timer of the coupler. More...
 
void stopLoadTimer (const MString &name) const
 Stop the load timer of the coupler. More...
 

Private Member Functions

void restrictData (const MInt level)
 Restrict the data (fine-coarse) on the given level. More...
 
void computeCoarseLevelCorrection (const MInt level)
 Compute the coarse level correction tau. More...
 
void storeRestrictedVariables (const MInt level)
 Store the restricted variables (required for the prolongation) More...
 
void prolongData (const MInt level)
 Prolong the data of a coarse level. More...
 
void correctCoarseBndryCells (const MInt solverId)
 
void resetSecondaryFlowVariables ()
 for each solver except the finest, reset variables to NaN to ensure that only restricted information is used More...
 
void resetMultiLevelVariables ()
 for each solver, reset multilevel variables More...
 
void initLeafCells ()
 store internal leaf cells for each solver except for finest solver, for which they are not needed More...
 
void initMapping ()
 for each coarse solver, store cell map to next finer solver More...
 
void initSplitMapping ()
 for each coarse solver, store cell map of split-cells to next finer solver childs More...
 
void initRestrictedCells ()
 for each solver that will be restricted (all except the coarsest), store restricted cells More...
 
void sanityCheck (const MInt mode=0)
 
MInt timer (const MString &name)
 
MIntcreateTimer (const MString &name)
 
void initTimers ()
 

Private Attributes

std::map< MString, MIntm_timers {}
 
MInt m_timerGroup = -1
 
std::vector< std::vector< MInt > > m_leafCells {}
 
std::vector< std::vector< MInt > > m_coarse2fine {}
 
std::vector< std::vector< MInt > > m_fine2coarse {}
 
std::vector< std::vector< MInt > > m_restrictedCells {}
 
std::vector< std::vector< MInt > > m_splitCellMapping {}
 
MInt m_prolongationMethod = false
 
MBool m_correctCoarseBndry = false
 

Additional Inherited Members

- Protected Member Functions inherited from CouplingFv< nDim, SysEqn >
MInt noSolvers () const
 
solverTypefvSolver (const MInt solverId=0) const
 
MInt a_noFvCells () const
 
MInt a_noFvGridCells () const
 
- Protected Member Functions inherited from Coupling
MFloat returnLoadRecord () const
 
MFloat returnIdleRecord () const
 
- Protected Attributes inherited from CouplingFv< nDim, SysEqn >
std::vector< solverType * > m_fvSolvers {}
 

Detailed Description

template<MInt nDim, class SysEqn>
class CouplerFvMultilevel< nDim, SysEqn >

Definition at line 30 of file couplerfvmultilevel.h.

Member Typedef Documentation

◆ Base

template<MInt nDim, class SysEqn >
using CouplerFvMultilevel< nDim, SysEqn >::Base = Coupling

Definition at line 32 of file couplerfvmultilevel.h.

◆ BaseFv

template<MInt nDim, class SysEqn >
using CouplerFvMultilevel< nDim, SysEqn >::BaseFv = CouplingFv<nDim, SysEqn>

Definition at line 33 of file couplerfvmultilevel.h.

◆ Grid

template<MInt nDim, class SysEqn >
using CouplerFvMultilevel< nDim, SysEqn >::Grid = CartesianGrid<nDim>

Definition at line 35 of file couplerfvmultilevel.h.

◆ GridProxy

template<MInt nDim, class SysEqn >
using CouplerFvMultilevel< nDim, SysEqn >::GridProxy = typename SolverType::GridProxy

Definition at line 36 of file couplerfvmultilevel.h.

◆ SolverType

template<MInt nDim, class SysEqn >
using CouplerFvMultilevel< nDim, SysEqn >::SolverType = typename BaseFv::solverType

Definition at line 34 of file couplerfvmultilevel.h.

Constructor & Destructor Documentation

◆ CouplerFvMultilevel()

template<MInt nDim, class SysEqn >
CouplerFvMultilevel< nDim, SysEqn >::CouplerFvMultilevel ( const MInt  couplingId,
std::vector< FvCartesianSolverXD< nDim, SysEqn > * >  solvers 
)

Constructor only stores arguments. All non-trivial initialization is performed in init().

Author
Michael Schlottke-Lakemper (mic) mic@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de
Date
2018-10-01

Definition at line 20 of file couplerfvmultilevel.cpp.

22 : Base(couplingId), BaseFv(couplingId, solvers, solvers.size()) {
23 TRACE();
24
25 // Initialize timers
26 initTimers();
27}
CouplingFv< nDim, SysEqn > BaseFv
MInt * solvers
Definition: maiatypes.h:72

◆ ~CouplerFvMultilevel()

template<MInt nDim, class SysEqn >
CouplerFvMultilevel< nDim, SysEqn >::~CouplerFvMultilevel

Definition at line 31 of file couplerfvmultilevel.cpp.

31 {
32 TRACE();
33
34 // Stop coupler timer
35 RECORD_TIMER_STOP(timer("Total"));
36}
MInt timer(const MString &name)

Member Function Documentation

◆ checkProperties()

template<MInt nDim, class SysEqn >
void CouplerFvMultilevel< nDim, SysEqn >::checkProperties ( )
inlineoverridevirtual

Implements Coupling.

Definition at line 56 of file couplerfvmultilevel.h.

56{};

◆ cleanUp()

template<MInt nDim, class SysEqn >
void CouplerFvMultilevel< nDim, SysEqn >::cleanUp ( )
inlinevirtual

Implements Coupling.

Definition at line 51 of file couplerfvmultilevel.h.

51{};

◆ computeCoarseLevelCorrection()

template<MInt nDim, class SysEqn >
void CouplerFvMultilevel< nDim, SysEqn >::computeCoarseLevelCorrection ( const MInt  level)
private

Definition at line 437 of file couplerfvmultilevel.cpp.

437 {
438 TRACE();
439
440 startTimer("ComputeCoarseCorrection");
441
442 // Store references and variables for convenience
443 auto& coarse = fvSolver(level);
444
445 // Calculate coarse level correction "tau"
446 // only required for internal cells, as the runge-Kutta step is only performed for those
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);
450 }
451 }
452
453 stopTimer("ComputeCoarseCorrection");
454}
solverType & fvSolver(const MInt solverId=0) const
Definition: coupling.h:386
MBool stopTimer(const MString &name)
MBool startTimer(const MString &name)
int32_t MInt
Definition: maiatypes.h:62
void const MInt cellId
Definition: collector.h:239

◆ correctCoarseBndryCells()

template<MInt nDim, class SysEqn >
void CouplerFvMultilevel< nDim, SysEqn >::correctCoarseBndryCells ( const MInt  solverId)
private

corrects the volume and the center of gravity of the boundary cells using fine cell information creates body surfaces using fine cell information does not work correctly with multipleGhostCell formulation (claudia)! See D.Hartman et al Computers & Fluids 37 (2008) 1103-1125: concept of averaged control volumes it is required that small and master cells are not yet merged!!!

Author
Daniel Hartmann, March 10, 2006, Tim Wegmann

Definition at line 961 of file couplerfvmultilevel.cpp.

961 {
962 TRACE();
963
964 auto& fine = fvSolver(solverId - 1);
965 auto& coarse = fvSolver(solverId);
966
967 if(coarse.domainId() == 0 && globalTimeStep < 1) {
968 cerr << "Correxting secondary bndry-cell volumes and centers " << endl;
969 }
970
971 const MInt noCoarseCells = coarse.a_noCells();
972 ScratchSpace<MFloat> bndryCoordinates(noCoarseCells, nDim, AT_, "bndryCoordinates");
973 ScratchSpace<MFloat> cellCoordinates(noCoarseCells, nDim, AT_, "cellCoordinates");
974 ScratchSpace<MFloat> srfcCoordinates(noCoarseCells, nDim, AT_, "srfcCoordinates");
975 ScratchSpace<MFloat> volumes(noCoarseCells, AT_, "volumes");
976
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);
982
983 // loop over all boundary cells on coarse solver
984 for(MInt bndryId = 0; bndryId < coarse.m_bndryCells->size(); bndryId++) {
985 // choose only those boundary cells at the current level
986 const MInt coarseCellId = coarse.m_bndryCells->a[bndryId].m_cellId;
987 ASSERT(coarseCellId > -1, "");
988 if(!coarse.c_isLeafCell(coarseCellId)) {
989 continue;
990 }
991
992 if(coarse.a_isHalo(coarseCellId)) {
993 continue;
994 }
995 // NOTE: data is exchanged for halo-cells below as the different solvers might not have matching
996 // lower level halo-layers
997 const MInt fineCellId = m_coarse2fine[solverId][coarseCellId];
998 if(fineCellId < 0) {
999 continue;
1000 }
1001
1002 if(fine.grid().tree().hasChildren(fineCellId)) {
1003 const MInt noChildren = fine.grid().tree().noChildren(fineCellId);
1004 if(noChildren == 0) {
1005 continue;
1006 }
1007
1008 // reset temp. variables
1009 MFloat volume = 0;
1010 MFloat bndryCellVolumes = 0;
1011 MFloat srfcArea = 0;
1012
1013 array<MFloat, nDim> bndryXyz{};
1014 array<MFloat, nDim> cellXyz{};
1015 array<MFloat, nDim> srfcXyz{};
1016
1017 bndryXyz.fill(0);
1018 cellXyz.fill(0);
1019 srfcXyz.fill(0);
1020
1021 // -------- average children cell coordinates and volumes ---------
1022 for(MInt childId = 0; childId < IPOW2(nDim); childId++) {
1023 const MInt childCellId = fine.c_childId(fineCellId, childId);
1024 if(childCellId == -1) {
1025 continue;
1026 }
1027 if(fine.a_isInactive(childCellId)) {
1028 continue;
1029 }
1030
1031 ASSERT(fine.c_isLeafCell(childCellId), "");
1032
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;
1037
1038 for(MInt i = 0; i < nDim; i++) {
1039 bndryXyz.at(i) += fine.a_coordinate(childCellId, i) * fine.m_bndryCells->a[bndryCellId].m_volume;
1040 }
1041
1042 // average body surface of children
1043 srfcArea += fine.m_bndryCells->a[bndryCellId].m_srfcs[0]->m_area;
1044
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;
1048 }
1049
1050 } else {
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;
1055 }
1056 }
1057 }
1058
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;
1064 }
1065 // ----------------------------------------------------------------
1066
1067 // correct the coordinate shift of the boundary cell
1068 // set the coordinates of the boundary cell
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];
1073
1074
1075 bndryCoordinates(coarseCellId, i) = coarse.m_bndryCells->a[bndryId].m_coordinates[i];
1076 cellCoordinates(coarseCellId, i) = cellXyz[i];
1077 srfcCoordinates(coarseCellId, i) = srfcXyz[i];
1078 }
1079
1080 // update coarse cell volume
1081 coarse.m_bndryCells->a[bndryId].m_volume = volume;
1082
1083 volumes(coarseCellId) = volume;
1084 }
1085 }
1086
1087 // exchange data
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);
1092
1093 // set data for halo cells
1094 for(MInt bndryId = 0; bndryId < coarse.m_bndryCells->size(); bndryId++) {
1095 const MInt coarseCellId = coarse.m_bndryCells->a[bndryId].m_cellId;
1096
1097 if(coarseCellId < 0) {
1098 continue;
1099 }
1100 if(!coarse.a_isHalo(coarseCellId)) {
1101 continue;
1102 }
1103 if(coarse.a_level(coarseCellId) != coarse.maxLevel()) {
1104 continue;
1105 }
1106
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);
1111 }
1112
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);
1115 }
1116
1117 coarse.computeCellVolumes();
1118}
std::vector< std::vector< MInt > > m_coarse2fine
This class is a ScratchSpace.
Definition: scratch.h:758
MInt globalTimeStep
constexpr MLong IPOW2(MInt x)
double MFloat
Definition: maiatypes.h:52

◆ createTimer()

template<MInt nDim, class SysEqn >
MInt & CouplerFvMultilevel< nDim, SysEqn >::createTimer ( const MString name)
private

Definition at line 1235 of file couplerfvmultilevel.cpp.

1235 {
1236 TRACE();
1237
1238 // First ensure that there are no name conflicts
1239 if(m_timers.count(name) > 0) {
1240 TERMM(1, "Timer '" + name + "' already exists.");
1241 }
1242
1243 // Create new timer and initialize with dummy id
1244 m_timers[name] = -1;
1245
1246 // Return reference to timer id
1247 return m_timers[name];
1248}
std::map< MString, MInt > m_timers

◆ finalizeAdaptation()

template<MInt nDim, class SysEqn >
void CouplerFvMultilevel< nDim, SysEqn >::finalizeAdaptation ( MInt  solverId)
virtual

Reimplemented from Coupling.

Definition at line 126 of file couplerfvmultilevel.cpp.

126 {
127 if(solverId == fvSolver(noSolvers() - 1).solverId()) {
128 // after all solvers finished their finalization
129
130 m_restrictedCells.clear();
131 m_coarse2fine.clear();
132 m_fine2coarse.clear();
133 m_leafCells.clear();
134 m_splitCellMapping.clear();
135
137
138 initMapping();
139
141
142 if(globalTimeStep < 0) {
144
146 }
147 }
148}
std::vector< std::vector< MInt > > m_leafCells
void initRestrictedCells()
for each solver that will be restricted (all except the coarsest), store restricted cells
std::vector< std::vector< MInt > > m_fine2coarse
void initLeafCells()
store internal leaf cells for each solver except for finest solver, for which they are not needed
void resetSecondaryFlowVariables()
for each solver except the finest, reset variables to NaN to ensure that only restricted information ...
std::vector< std::vector< MInt > > m_restrictedCells
void initMapping()
for each coarse solver, store cell map to next finer solver
MInt noSolvers() const
Definition: coupling.h:385
void resetMultiLevelVariables()
for each solver, reset multilevel variables
std::vector< std::vector< MInt > > m_splitCellMapping

◆ finalizeCouplerInit()

template<MInt nDim, class SysEqn >
void CouplerFvMultilevel< nDim, SysEqn >::finalizeCouplerInit
virtual

Implements Coupling.

Definition at line 99 of file couplerfvmultilevel.cpp.

99 {
100 // for initial adaptation, check again
101 if(fvSolver(0).m_adaptation && globalTimeStep == 0) {
102 sanityCheck(1);
103 }
104
105 if(m_correctCoarseBndry && !fvSolver(0).m_levelSetMb) {
106 for(MInt solverId = 1; solverId < noSolvers(); solverId++) {
107 correctCoarseBndryCells(solverId);
108 }
109 }
110
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;
117 }
118 }
119 }
120
122}
void correctCoarseBndryCells(const MInt solverId)
void initSplitMapping()
for each coarse solver, store cell map of split-cells to next finer solver childs

◆ finalizeSubCoupleInit()

template<MInt nDim, class SysEqn >
void CouplerFvMultilevel< nDim, SysEqn >::finalizeSubCoupleInit ( MInt  )
inlinevirtual

Implements Coupling.

Definition at line 46 of file couplerfvmultilevel.h.

46{};

◆ fvSolver()

template<MInt nDim, class SysEqn >
solverType & CouplingFv< nDim, SysEqn >::fvSolver ( const MInt  solverId = 0) const
inline

Definition at line 386 of file coupling.h.

386 {
387 ASSERT(solverId < noSolvers(), "Invalid solverId " + std::to_string(solverId) + "/" + std::to_string(noSolvers()));
388 return *m_fvSolvers[solverId];
389 }
std::vector< solverType * > m_fvSolvers
Definition: coupling.h:395

◆ getDomainDecompositionInformation()

template<MInt nDim, class SysEqn >
void CouplerFvMultilevel< nDim, SysEqn >::getDomainDecompositionInformation ( std::vector< std::pair< MString, MInt > > &  NotUseddomainInfo)
inlineoverridevirtual

Reimplemented from Coupling.

Definition at line 52 of file couplerfvmultilevel.h.

52{};

◆ init()

template<MInt nDim, class SysEqn >
void CouplerFvMultilevel< nDim, SysEqn >::init ( )
overridevirtual

Implements Coupling.

◆ initLeafCells()

template<MInt nDim, class SysEqn >
void CouplerFvMultilevel< nDim, SysEqn >::initLeafCells
private

Definition at line 871 of file couplerfvmultilevel.cpp.

871 {
872 TRACE();
873
874 // Count internal leaf cells in each solver except for finest solver, for which they are not needed
875 std::vector<MInt> noLeafCells(noSolvers(), 0);
876 for(MInt solverId = 1; solverId < noSolvers(); solverId++) {
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]++;
881 }
882 }
883 }
884
885 m_leafCells.resize(noSolvers());
886 for(MInt solverId = 1; solverId < noSolvers(); solverId++) {
887 m_leafCells[solverId].resize(noLeafCells[solverId]);
888 const MInt noInternalCells = fvSolver(solverId).grid().noInternalCells();
889 MInt index = 0;
890 for(MInt i = 0; i < noInternalCells; i++) {
891 if(fvSolver(solverId).grid().tree().isLeafCell(i)) {
892 m_leafCells[solverId][index] = i;
893 index++;
894 }
895 }
896 }
897}
constexpr GridProxy & grid() const
IdType index(const FloatType *const x, const IdType level)
Return Hilbert index for given location and level in 2D or 3D.
Definition: hilbert.h:165

◆ initMapping()

template<MInt nDim, class SysEqn >
void CouplerFvMultilevel< nDim, SysEqn >::initMapping
private

Definition at line 774 of file couplerfvmultilevel.cpp.

774 {
775 TRACE();
776
777 m_coarse2fine.resize(noSolvers());
778 for(MInt solverId = 1; solverId < noSolvers(); solverId++) {
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));
785 }
786 }
787
788 // based on restricted cells/restricted Id, so only for the number of restricted cells!
789 m_fine2coarse.resize(noSolvers());
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));
798 }
799 }
800}

◆ initRestrictedCells()

template<MInt nDim, class SysEqn >
void CouplerFvMultilevel< nDim, SysEqn >::initRestrictedCells
private

Definition at line 746 of file couplerfvmultilevel.cpp.

746 {
747 TRACE();
748
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;
754
755 // First, count restricted cells and store them temporarily
756 MInt noRestrictedCells = 0;
757 MIntScratchSpace restrictedCells(noInternalCells, AT_, "restrictedCells");
758 for(MInt i = 0; i < noInternalCells; i++) {
759 if(fineGrid.tree().level(i) == restrictedLevel && fineGrid.tree().hasChildren(i)) {
760 restrictedCells[noRestrictedCells] = i;
761 noRestrictedCells++;
762 }
763 }
764
765 // Second, move recorded cells to permanent storage
766 m_restrictedCells[solverId].resize(noRestrictedCells);
767 copy_n(restrictedCells.data(), noRestrictedCells, m_restrictedCells[solverId].data());
768 }
769}

◆ initSplitMapping()

template<MInt nDim, class SysEqn >
void CouplerFvMultilevel< nDim, SysEqn >::initSplitMapping
private

Definition at line 805 of file couplerfvmultilevel.cpp.

805 {
806 TRACE();
807
808 m_splitCellMapping.clear();
810 for(MInt solverId = 1; solverId < noSolvers(); solverId++) {
811 auto& fine = fvSolver(solverId - 1);
812 auto& coarse = fvSolver(solverId);
813 if(coarse.m_totalnosplitchilds == 0) {
814 continue;
815 }
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;
824 // loop over all fine-cell childs and find child with lowest distance to the split-child
825 for(MInt childId = 0; childId < IPOW2(nDim); childId++) {
826 const MInt child = fine.c_childId(fineCell, childId);
827 if(child == -1) {
828 continue;
829 }
830 MFloat dist = 0;
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++) {
836 dist = 0;
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));
840 }
841 dist = sqrt(dist);
842 distances.insert(make_pair(dist, splitChild));
843 }
844 }
845 }
846 continue;
847 }
848 if(fine.a_isInactive(child)) {
849 continue;
850 }
851 for(MInt i = 0; i < nDim; i++) {
852 dist += POW2(coarse.a_coordinate(splitChild, i) - fine.a_coordinate(child, i));
853 }
854 dist = sqrt(dist);
855 distances.insert(make_pair(dist, child));
856 }
857
858 if(distances.empty()) {
859 cerr << "Neighbor search necessary!" << distances.size() << " " << distances.begin()->second << " "
860 << coarse.a_isHalo(splitCell) << endl;
861 }
862
863 const MInt childId = distances.begin()->second;
864 m_splitCellMapping[solverId][totalSplitId++] = childId;
865 }
866 }
867 }
868}
constexpr Real POW2(const Real x)
Definition: functions.h:119
MFloat dist(const Point< DIM > &p, const Point< DIM > &q)
Definition: pointbox.h:54

◆ initTimers()

template<MInt nDim, class SysEqn >
void CouplerFvMultilevel< nDim, SysEqn >::initTimers
private

Definition at line 1272 of file couplerfvmultilevel.cpp.

1272 {
1273 TRACE();
1274
1275 // Create timer group & timer for coupler, and start the timer
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"));
1279
1280 // Timer for initialization
1281 NEW_SUB_TIMER_NOCREATE(createTimer("Init"), "Initialization", timer("Total"));
1282
1283 // Create timer for performance-relevant run information
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"));
1288
1289 // Restriction
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"));
1298
1299 // Prolongation
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"));
1306}
MInt & createTimer(const MString &name)

◆ noSolvers()

template<MInt nDim, class SysEqn >
MInt CouplingFv< nDim, SysEqn >::noSolvers ( ) const
inline

Definition at line 385 of file coupling.h.

385{ return m_fvSolvers.size(); }

◆ postCouple()

template<MInt nDim, class SysEqn >
void CouplerFvMultilevel< nDim, SysEqn >::postCouple ( MInt  )
overridevirtual

Implements Coupling.

Reimplemented in CouplerFvMultilevelInterpolation< nDim, SysEqn >.

Definition at line 170 of file couplerfvmultilevel.cpp.

170 {
171 TRACE();
172 startTimer("Main");
173
174 // Determine currently active solver/level via the solvers status
175 MInt activeLevel = -1;
176 for(MInt solverId = 0; solverId < noSolvers(); solverId++) {
177 if(fvSolver(solverId).getSolverStatus()) {
178 activeLevel = solverId;
179 break;
180 }
181 }
182 if(activeLevel == -1) {
183 TERMM(1, "Multilevel postCouple(): no active solver/level found!");
184 }
185
186 // Restrict solution unless if this is the coarsest level (sawtooth cycle)
187 if(activeLevel != noSolvers() - 1) {
188 restriction(activeLevel);
189 } else {
190 for(MInt i = noSolvers() - 1; i > 0; i--) {
191 prolongation(i);
192 }
193 }
194
195 stopTimer("Main");
196}
void prolongation(const MInt level)
Prolong the solution on the given coarse level onto the next finer level.
void restriction(const MInt level)
Restrict the solution on the given fine level onto the next coarser level.
MBool getSolverStatus()
Get the solver status indicating if the solver is currently active in the execution recipe.
Definition: solver.h:401

◆ preCouple()

template<MInt nDim, class SysEqn >
void CouplerFvMultilevel< nDim, SysEqn >::preCouple ( MInt  solverId)
overridevirtual

Implements Coupling.

Definition at line 152 of file couplerfvmultilevel.cpp.

152 {
153 // apply coarse boundary correction to all secondary solvers after the primary solver pre-time step
154 if(solverId == fvSolver(0).solverId()) {
155 // correct every time step only after it has been updated in the primary solver
156 if(m_correctCoarseBndry && fvSolver(0).m_levelSetMb
157 && (fvSolver(0).m_reComputedBndry || globalTimeStep == fvSolver(0).m_restartTimeStep)) {
158 for(MInt solver = 1; solver < noSolvers(); solver++) {
160 }
161 }
162 }
163
164 if(fvSolver(0).m_reComputedBndry || globalTimeStep == fvSolver(0).m_restartTimeStep) {
166 }
167}

◆ prolongation()

template<MInt nDim, class SysEqn >
void CouplerFvMultilevel< nDim, SysEqn >::prolongation ( const MInt  level)

Definition at line 492 of file couplerfvmultilevel.cpp.

492 {
493 TRACE();
494
495 startTimer("Prolongation");
496
497 // Store references and variables for convenience
498 auto& coarse = static_cast<SolverType&>(fvSolver(level));
499 auto& fine = static_cast<SolverType&>(fvSolver(level - 1));
500
501 // only halo cells only primary variables are correct at this point!
502 if(m_prolongationMethod == 2) {
503 // Temporarily store gradients
504 startTimer("StoreGradients");
505 const MInt noCells = coarse.noInternalCells();
506 const MInt noVars = coarse.CV->noVariables;
507 MFloatScratchSpace slopes(noCells * noVars * nDim, AT_, "slopes");
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);
512 }
513 }
514 }
515 stopTimer("StoreGradients");
516
517 // Calculate new gradients after the completed coarse time step
518 startTimer("CalcGradientsProlongation");
519 coarse.LSReconstructCellCenterCons(0);
520 stopTimer("CalcGradientsProlongation");
521
522 // Compute delta in gradients
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];
528 }
529 }
530 }
531 stopTimer("CalcGradientDelta");
532 }
533
534 prolongData(level);
535
536 // Re-compute boundary conditions etc. based on new/corrected variable state in the fine cell
537 startTimer("FineLhsBnd");
538 fine.exchangeData(&fine.a_variable(0, 0), fine.CV->noVariables);
539
540 fine.lhsBnd();
541
542 stopTimer("FineLhsBnd");
543
544 stopTimer("Prolongation");
545}
void prolongData(const MInt level)
Prolong the data of a coarse level.
SolverType
Definition: enums.h:22

◆ prolongData()

template<MInt nDim, class SysEqn >
void CouplerFvMultilevel< nDim, SysEqn >::prolongData ( const MInt  level)
private

Definition at line 550 of file couplerfvmultilevel.cpp.

550 {
551 TRACE();
552
553 startTimer("ProlongData");
554
555 // Store references and variables for convenience
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();
562
563 // compute difference to the restricted variables on the coarse grid
564 // necessary on halo and ghost-cells as their change might be required for interpolation!
565 for(MInt cellId = 0; cellId < coarse.a_noCells(); cellId++) {
566 if(cellId < coarse.c_noCells() && !coarse.c_isLeafCell(cellId)) {
567 continue;
568 }
569 for(MInt varId = 0; varId < noVars; varId++) {
570 coarse.a_variable(cellId, varId) -= coarse.a_restrictedVar(cellId, varId);
571 }
572 }
573
574
575 // Reset restricted cell variables in fine solver
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;
581 }
582 }
583
584 // Add coarse-level correction to cells on fine level and copy slopes
585 for(MInt cellId = 0; cellId < noInternalCells; cellId++) {
586 const MInt fineCellId = m_coarse2fine[coarseLevel][cellId];
587 switch(m_prolongationMethod) {
588 case 0:
589 case 1: {
590 for(MInt varId = 0; varId < noVars; varId++) {
591 fine.a_variable(fineCellId, varId) += coarse.a_variable(cellId, varId);
592 }
593 break;
594 }
595 case 2: {
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);
600 }
601 }
602 break;
603 }
604 default: {
605 mTerm(1, AT_, "Unknown prolongation method");
606 }
607 }
608 }
609
610 std::function<MFloat(const MInt, const MInt)> consVar = [&](const MInt cellId, const MInt varId) {
611 return static_cast<MFloat>(coarse.a_variable(cellId, varId));
612 };
613
614 std::function<MFloat(const MInt, const MInt)> coordinate = [&](const MInt cellId, const MInt id) {
615 return static_cast<MFloat>(coarse.a_coordinate(cellId, id));
616 };
617
618
619 // interpolate correction from restricted cells to their children
620 for(MInt restrictedId = 0; restrictedId < noRestrictedCells; restrictedId++) {
621 const MInt cellId = m_restrictedCells[fineLevel][restrictedId];
622 const MInt coarseCellId = m_fine2coarse[fineLevel][restrictedId];
623
624 // Loop over child cells to prolong correction
625 for(MInt childId = 0; childId < IPOW2(nDim); childId++) {
626 // Skip if child does not exist
627 const MInt child = fine.c_childId(cellId, childId);
628 if(child == -1) {
629 continue;
630 }
631 if(fine.a_isInactive(child)) {
632 continue;
633 }
634
635 switch(m_prolongationMethod) {
636 case 0: {
637 for(MInt varId = 0; varId < noVars; varId++) {
638 fine.a_variable(child, varId) += fine.a_variable(cellId, varId);
639 }
640 break;
641 }
642 case 1: {
643 MInt interpolationCells[8] = {-1, -1, -1, -1, -1, -1, -1, -1};
644 MFloat point[nDim];
645 for(MInt i = 0; i < nDim; i++) {
646 point[i] = fine.a_coordinate(child, i);
647 }
648 if(!fine.a_isBndryCell(child)) {
649 // 1) find regular Cartesian stencil
650
651 // NOTE: prevent access to inactive neighbors here
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; };
655
656 const MInt position =
657 coarse.setUpInterpolationStencil(coarseCellId, interpolationCells, point, alwaysTrue, false);
658 coarse.m_deleteNeighbour = backup;
659
660 ASSERT(position > -1, "Return value of setUpInterpolationStencil is > -1");
661
662 // 2) stencil check:
663 // - replace inactive cell with bndry-ghost cell of the coarse cell
664 // - replace with bndry ghost cell if a small-cell
665 // NOTE: possible alternative would be the ghost cell of the largest cell the stencil!
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!");
670 }
671
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) {
677 // meaning not a split-cell
678 interpolationCells[id] = ghostCellId;
679 }
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;
687 }
688 }
689 }
690
691 // use least-squares interpolation
692 // NOTE: other alternatives could be a cartesian-interpolation
693 for(MInt varId = 0; varId < noVars; varId++) {
694 fine.a_variable(child, varId) +=
695 coarse.leastSquaresInterpolation(&interpolationCells[0], &point[0], varId, consVar, coordinate);
696 }
697 } else {
698 // change stencil when the cell is a bndry-Cell
699 const MInt position = coarse.setUpBndryInterpolationStencil(coarseCellId, interpolationCells, point);
700
701 for(MInt id = 0; id < IPOW2(nDim); id++) {
702 const MInt intCellId = interpolationCells[id];
703 if(intCellId < 0) {
704 cerr << position << " " << coarseCellId << " " << coarse.domainId() << endl;
705 mTerm(1, AT_, "Incorrect stencil at bndry!");
706 } else {
707 ASSERT(!coarse.a_isInactive(intCellId), "");
708 }
709 }
710
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);
715 }
716 }
717 break;
718 }
719 case 2: {
720 // Compute distance between cell centers based on the volumetric coordinates
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);
724 }
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);
729 }
730 }
731 break;
732 }
733 default: {
734 mTerm(1, AT_, "Unknown prolongation method");
735 }
736 }
737 }
738 }
739
740 stopTimer("ProlongData");
741}
void mTerm(const MInt errorCode, const MString &location, const MString &message)
Definition: functions.cpp:29
bool MBool
Definition: maiatypes.h:58
MInt id
Definition: maiatypes.h:71

◆ readProperties()

template<MInt nDim, class SysEqn >
void CouplerFvMultilevel< nDim, SysEqn >::readProperties ( )
inlineoverridevirtual

Implements Coupling.

Definition at line 55 of file couplerfvmultilevel.h.

55{};

◆ resetMultiLevelVariables()

template<MInt nDim, class SysEqn >
void CouplerFvMultilevel< nDim, SysEqn >::resetMultiLevelVariables
private

Definition at line 901 of file couplerfvmultilevel.cpp.

901 {
902 TRACE();
903
904 const auto nan = std::numeric_limits<MFloat>::quiet_NaN();
905 for(MInt solverId = 0; solverId < noSolvers(); solverId++) {
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;
916 }
917 }
918 }
919 }
920}

◆ resetSecondaryFlowVariables()

template<MInt nDim, class SysEqn >
void CouplerFvMultilevel< nDim, SysEqn >::resetSecondaryFlowVariables
private

Definition at line 925 of file couplerfvmultilevel.cpp.

925 {
926 TRACE();
927
928 const auto nan = std::numeric_limits<MFloat>::quiet_NaN();
929
930 for(MInt solverId = 1; solverId < noSolvers(); solverId++) {
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;
940 }
941 }
942
943 for(MInt varId = 0; varId < noVars; varId++) {
944 current.a_pvariable(cellId, varId) = nan;
945 }
946 }
947 }
948}

◆ resetTau()

template<MInt nDim, class SysEqn >
void CouplerFvMultilevel< nDim, SysEqn >::resetTau ( const MInt  level)

Definition at line 263 of file couplerfvmultilevel.cpp.

263 {
264 TRACE();
265
266 auto& coarse = fvSolver(level);
267 const MInt noVars = coarse.CV->noVariables;
268
269 // Reset coarse level correction "tau"
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;
274 }
275 }
276}

◆ restrictData()

template<MInt nDim, class SysEqn >
void CouplerFvMultilevel< nDim, SysEqn >::restrictData ( const MInt  level)
private

Definition at line 281 of file couplerfvmultilevel.cpp.

281 {
282 TRACE();
283
284 startTimer("RestrictData");
285
286 // Store references and variables for convenience
287 auto& fine = fvSolver(level);
288 auto& coarse = fvSolver(level + 1);
289 const MInt noVars = fine.CV->noVariables;
290
291 ScratchSpace<MFloat> sumVolumes(fine.noInternalCells(), AT_, "sumVolumes");
292 std::fill_n(&sumVolumes[0], fine.noInternalCells(), std::numeric_limits<MFloat>::quiet_NaN());
293
294 // Initialize cell volumes on fine grid with the coarse grid cell volumes, if a matching fine grid
295 // cell has children this value will be overwritten below by the sum of volumes of the child cells
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);
299 }
300
301 // First, loop over all cells of the fine solver that need to be restricted to and restrict their
302 // child cells' data
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];
307
308 // Reset all relevant variables
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;
315 }
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;
320 }
321 }
322
323 sumVolumes[cellId] = 0;
324
325 // Loop over child cells
326 MFloat volume = 0.0;
327 for(MInt childId = 0; childId < IPOW2(nDim); childId++) {
328 // Skip if child does not exist
329 const MInt child = fine.c_childId(cellId, childId);
330 if(child == -1) {
331 continue;
332 }
333 if(fine.a_isInactive(child)) {
334 continue;
335 }
336
337 // Update total volume of restricted cells
338 const MFloat childVolume = fine.a_cellVolume(child);
339 volume += childVolume;
340 sumVolumes[cellId] += childVolume;
341
342 // Restrict data by volume average of the child data
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;
349 }
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];
354 }
355 }
356 }
357
358 // Volume-average variables
359 if(volume > 0) {
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;
366 }
367 }
368 } else {
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);
373 }
374 }
375 }
376
377 // parent/coarse cells which do not have
378 ASSERT(childLessCells.empty(), "Warning, not matching children have been found for a multi-level solver");
379
380 // Next, copy all data from fine to coarse solver and store restricted RHS
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);
389 }
390
391 // Volume weighting factor for restricting the RHS and tau
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));
399 }
400 }
401 }
402
403 // update coarse split children based on closes finer child
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);
415 }
416 // Volume weighting factor for restricting the RHS and tau
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));
425 }
426 }
427 }
428 }
429
430
431 stopTimer("RestrictData");
432}

◆ restriction()

template<MInt nDim, class SysEqn >
void CouplerFvMultilevel< nDim, SysEqn >::restriction ( const MInt  level)

Definition at line 201 of file couplerfvmultilevel.cpp.

201 {
202 TRACE();
203
204 startTimer("Restriction");
205
206 // Sanity check for argument
207 if(level < 0 || level > noSolvers() - 2) {
208 TERMM(1,
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: "
211 + to_string(level));
212 }
213
214 const MInt fineLevel = level;
215 const MInt coarseLevel = level + 1;
216 auto& fine = fvSolver(fineLevel);
217 auto& coarse = fvSolver(coarseLevel);
218
219 // re-Compute the right-hand side at fine level for restriction
220 startTimer("ComputeFineRHS");
221 fine.rhs();
222 fine.rhsBnd();
223 stopTimer("ComputeFineRHS");
224
225 // Restrict data from fine to coarse level and store restricted RHS
226 restrictData(fineLevel);
227
228 coarse.exchangeData(&coarse.a_variable(0, 0), coarse.CV->noVariables);
229 coarse.exchangeData(&coarse.a_oldVariable(0, 0), coarse.CV->noVariables);
230
231 // Run lhsBnd to apply small cell correction and exchange data after restriction
232 startTimer("ComputeCoarseLhsBnd");
233 coarse.lhsBnd();
234
235 stopTimer("ComputeCoarseLhsBnd");
236
237 if(m_prolongationMethod == 2) {
238 // Calculate and store the gradients on the coarse grid based on the new restricted data
239 startTimer("CalcGradientsRestriction");
240 coarse.LSReconstructCellCenterCons(0);
241 stopTimer("CalcGradientsRestriction");
242 }
243
244 // Re-calculate the residual of the coarse solver
245 coarse.rhs();
246 coarse.rhsBnd();
247
248 // Calculate coarse grid correction factor
249 // (i.e. recompute the residual and compute the difference between the new residual
250 // and the residual
251 computeCoarseLevelCorrection(coarseLevel);
252
253 // Store restricted variables
254 // (i.e. store variables in the coarse grid after the restriction before the coarse time step!)
255 storeRestrictedVariables(coarseLevel);
256
257 stopTimer("Restriction");
258}
void restrictData(const MInt level)
Restrict the data (fine-coarse) on the given level.
void storeRestrictedVariables(const MInt level)
Store the restricted variables (required for the prolongation)
void computeCoarseLevelCorrection(const MInt level)
Compute the coarse level correction tau.

◆ sanityCheck() [1/2]

template<MInt nDim, class SysEqn >
void CouplerFvMultilevel< nDim, SysEqn >::sanityCheck ( )

◆ sanityCheck() [2/2]

template<MInt nDim, class SysEqn >
void CouplerFvMultilevel< nDim, SysEqn >::sanityCheck ( const MInt  mode = 0)
private

Perform different checks to ensure that everything is properly initialized and configured. mode 0: skip checks if the solver cells are created during the initial adaptation mode 1: second call after the initial adaptation (=> don't skip checks!)

Author
Michael Schlottke-Lakemper (mic) mic@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de
Date
2018-10-01

Definition at line 1128 of file couplerfvmultilevel.cpp.

1128 {
1129 TRACE();
1130
1131 // Check #1: Ensure that no small boundary cells are detected
1132 // (they are not yet handled properly)
1133 for(MInt i = 0; i < noSolvers(); i++) {
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");
1137 }
1138 if(!b.m_fvBndryCnd->m_smallCutCells.empty()) {
1139 cerr << "Multilevel: small cells might not be handled properly yet, continue anyway..." << endl;
1140 }
1141 }
1142
1143 // Check #2: Ensure that we have at least two solvers
1144 if(noSolvers() < 2) {
1145 TERMM(1, "Multilevel computation does not make sense with less than two solvers");
1146 }
1147
1148 // if the solver cells are created during an initial adaptation the checks below need
1149 // to be done at a later point!
1150 if(mode == 0 && fvSolver(0).m_adaptation && globalTimeStep == 0) {
1151 return;
1152 }
1153
1154 // Check #3: Ensure that the maximum level is reduced by one with each solver and that the fv-solvers
1155 // are of the same type
1156 const MInt overallMaxLevel = fvSolver(0).grid().maxLevel();
1157 for(MInt solverId = 1; solverId < noSolvers(); solverId++) {
1158 if(fvSolver(solverId).grid().maxLevel() != overallMaxLevel - solverId) {
1159 TERMM(1,
1160 "Maximum refinement level not reduced by one between solvers " + to_string(solverId - 1) + " and "
1161 + to_string(solverId));
1162 }
1163 if(fvSolver(solverId).m_levelSetMb != fvSolver(0).m_levelSetMb) {
1164 TERMM(1, "Multilevel coupling of different fv-solver types not allowed yet!");
1165 }
1166 }
1167
1168 // Check #4: Make sure that for each solver that is restricted, the cells at the restricted level
1169 // match the leaf cells of the next coarser solver
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;
1173 MInt count = 0;
1174 for(MInt i = 0; i < noInternalCells; i++) {
1175 // Check all cells that are either at the restricted level or that are coarser and leaf cells,
1176 // as they should match the leaf cells of the next coarser solver
1177 if(fvSolver(solverId).grid().tree().level(i) == restrictedLevel
1178 || (fvSolver(solverId).grid().tree().level(i) < restrictedLevel
1179 && fvSolver(solverId).grid().tree().isLeafCell(i))) {
1180 // The grid cell id of the restricted cells should match the grid cell id of the leaf cell
1181 if(fvSolver(solverId).grid().tree().solver2grid(i)
1182 == fvSolver(solverId + 1).grid().tree().solver2grid(m_leafCells[solverId + 1][count])) {
1183 count++;
1184 } else {
1185 TERMM(1,
1186 "Mismatch between restricted cells of solver " + to_string(solverId) + " and leaf cells of solver "
1187 + to_string(solverId + 1));
1188 }
1189 }
1190 }
1191
1192 // Also check if count matches the total number of leaf cells of the coarse solver
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");
1195 }
1196 }
1197
1198
1199 if(mode == 1) {
1200 // Check #N: Ensure that "restricted" cells at level n are identical to leaf cells at level n + 1
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");
1213 }
1214 }
1215 }
1216}

◆ startTimer()

template<MInt nDim, class SysEqn >
MBool CouplerFvMultilevel< nDim, SysEqn >::startTimer ( const MString name)

Definition at line 1252 of file couplerfvmultilevel.cpp.

1252 {
1253 if(name.empty()) {
1254 TERMM(1, "Empty timer name");
1255 }
1256 RECORD_TIMER_START(timer(name));
1257 return true;
1258}

◆ stopTimer()

template<MInt nDim, class SysEqn >
MBool CouplerFvMultilevel< nDim, SysEqn >::stopTimer ( const MString name)

Definition at line 1262 of file couplerfvmultilevel.cpp.

1262 {
1263 if(name.empty()) {
1264 TERMM(1, "Empty timer name");
1265 }
1266 RECORD_TIMER_STOP(timer(name));
1267 return true;
1268}

◆ storeRestrictedVariables()

template<MInt nDim, class SysEqn >
void CouplerFvMultilevel< nDim, SysEqn >::storeRestrictedVariables ( const MInt  level)
private

There is an exception in the Enthalpy case where the conservative variables are exchanged!

Definition at line 459 of file couplerfvmultilevel.cpp.

459 {
460 TRACE();
461
462 startTimer("StoreRestrictedVars");
463
464 // Store references and variables for convenience
465 auto& coarse = fvSolver(level);
466
467 // compute conservative variables on halo cells
468 // before conservative variables have been transferred from the fine grid for all internal cells,
469 // primitive variables been calculated and primitive variables been exchanged
471
472 for(MInt cellId = coarse.noInternalCells(); cellId < coarse.a_noCells(); cellId++) {
473 coarse.setConservativeVariables(cellId);
474 }
475
476 // Store restricted variables for all cells, as halo information might bee needed for interpolation
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);
483 }
484 }
485
486 stopTimer("StoreRestrictedVars");
487}

◆ subCouple()

template<MInt nDim, class SysEqn >
void CouplerFvMultilevel< nDim, SysEqn >::subCouple ( MInt  ,
MInt  ,
std::vector< MBool > &   
)
inlineoverridevirtual

Implements Coupling.

Definition at line 49 of file couplerfvmultilevel.h.

49{};

◆ timer()

template<MInt nDim, class SysEqn >
MInt CouplerFvMultilevel< nDim, SysEqn >::timer ( const MString name)
private

Return existing timer id for given timer name or die.

Author
Michael Schlottke-Lakemper (mic) mic@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de
Date
2018-11-26
Parameters
[in]nameName of the timer. If it does not exist, MAIA aborts.

Definition at line 1226 of file couplerfvmultilevel.cpp.

1226 {
1227 if(m_timers.count(name) == 0) {
1228 TERMM(1, "Timer '" + name + "' does not exist.");
1229 }
1230 return m_timers.at(name);
1231}

Member Data Documentation

◆ m_coarse2fine

template<MInt nDim, class SysEqn >
std::vector<std::vector<MInt> > CouplerFvMultilevel< nDim, SysEqn >::m_coarse2fine {}
private

Definition at line 93 of file couplerfvmultilevel.h.

◆ m_correctCoarseBndry

template<MInt nDim, class SysEqn >
MBool CouplerFvMultilevel< nDim, SysEqn >::m_correctCoarseBndry = false
private

Definition at line 100 of file couplerfvmultilevel.h.

◆ m_fine2coarse

template<MInt nDim, class SysEqn >
std::vector<std::vector<MInt> > CouplerFvMultilevel< nDim, SysEqn >::m_fine2coarse {}
private

Definition at line 94 of file couplerfvmultilevel.h.

◆ m_leafCells

template<MInt nDim, class SysEqn >
std::vector<std::vector<MInt> > CouplerFvMultilevel< nDim, SysEqn >::m_leafCells {}
private

Definition at line 92 of file couplerfvmultilevel.h.

◆ m_prolongationMethod

template<MInt nDim, class SysEqn >
MInt CouplerFvMultilevel< nDim, SysEqn >::m_prolongationMethod = false
private

Definition at line 99 of file couplerfvmultilevel.h.

◆ m_restrictedCells

template<MInt nDim, class SysEqn >
std::vector<std::vector<MInt> > CouplerFvMultilevel< nDim, SysEqn >::m_restrictedCells {}
private

Definition at line 95 of file couplerfvmultilevel.h.

◆ m_splitCellMapping

template<MInt nDim, class SysEqn >
std::vector<std::vector<MInt> > CouplerFvMultilevel< nDim, SysEqn >::m_splitCellMapping {}
private

Definition at line 96 of file couplerfvmultilevel.h.

◆ m_timerGroup

template<MInt nDim, class SysEqn >
MInt CouplerFvMultilevel< nDim, SysEqn >::m_timerGroup = -1
private

Definition at line 88 of file couplerfvmultilevel.h.

◆ m_timers

template<MInt nDim, class SysEqn >
std::map<MString, MInt> CouplerFvMultilevel< nDim, SysEqn >::m_timers {}
private

Definition at line 87 of file couplerfvmultilevel.h.


The documentation for this class was generated from the following files: