22template <MInt nDim,
class SysEqn>
41template <MInt nDim,
class SysEqn>
44 m_noRKSteps = Context::getSolverProperty<MInt>(
"noRKSteps", upStream().solverId(), AT_, &m_noRKSteps);
46 ASSERT(m_noRKSteps == Context::getSolverProperty<MInt>(
"noRKSteps", downStream().solverId(), AT_, &m_noRKSteps),
"");
61 m_zonalMethod = Context::getSolverProperty<MString>(
"zonalMethod", couplerId(), AT_, &m_zonalMethod);
69 m_zonalDualTimeStepping =
70 Context::getSolverProperty<MBool>(
"zonalDualTimeStepping", couplerId(), AT_, &m_zonalDualTimeStepping);
72 if(m_zonalMethod ==
"P") {
82 m_zonalCoordinate = Context::getSolverProperty<MFloat>(
"zonalCoordinate", couplerId(), AT_);
95 m_zonalDir = Context::getSolverProperty<MInt>(
"zonalDir", couplerId(), AT_);
97 if(upStream().domainId() == 0) {
98 cerr <<
"Using cartesian zonal Method with plane-cut at " << m_zonalCoordinate <<
" in direction " << m_zonalDir
102 }
else if(m_zonalMethod ==
"B") {
104 mTerm(1, AT_,
"ZonalMethod not implemented yet!");
112template <MInt nDim,
class SysEqn>
114 createZonalMapping();
116 ASSERT(upStream().a_timeStepComputationInterval() == downStream().a_timeStepComputationInterval(),
"");
122template <MInt nDim,
class SysEqn>
124 if(solverLoopId >= m_upStreamId && solverLoopId >= m_downStreamId) {
125 createZonalMapping();
133template <MInt nDim,
class SysEqn>
135 if(solverLoopId >= m_upStreamId && solverLoopId >= m_downStreamId) {
136 createZonalMapping();
143template <MInt nDim,
class SysEqn>
145 std::vector<MBool>& ) {
147 if(recipeStep == 1 && (solverId == m_upStreamId || solverId == m_downStreamId)) {
150 if(m_RKStep == 2 * m_noRKSteps) {
152 exchangeZonalValues(-1);
155 exchangeZonalValues(solverId);
160 if(m_RKStep == 2 * m_noRKSteps && upStream().a_timeStepComputationInterval() > 0
161 &&
globalTimeStep % upStream().a_timeStepComputationInterval() == 0) {
170template <MInt nDim,
class SysEqn>
174 if(solverStep == 1) {
176 exchangeZonalValues(-1);
184template <MInt nDim,
class SysEqn>
186 if(solverStep == 1) {
187 if(upStream().isActive() && downStream().isActive()
188 && fabs(upStream().timeStep() - downStream().timeStep()) > upStream().m_eps) {
189 cerr << setprecision(16) <<
"UpStream-TimeStep " << upStream().timeStep() <<
" DownStream-TimeStep "
190 << upStream().timeStep() << endl;
191 mTerm(1, AT_,
"Time in Fv-Mb-Solvers differs!.");
200template <MInt nDim,
class SysEqn>
207 m_upStreamOffset = 0;
208 m_downStreamOffset = 0;
210 if(upStream().isActive()) {
211 if(m_zonalMethod ==
"P") {
214 for(
MInt upId = 0; upId < upStream().c_noCells(); upId++) {
215 if(upStream().a_coordinate(upId, m_zonalDir) > m_zonalCoordinate) {
216 MBool lastLayer =
false;
217 if(!upStream().a_hasNeighbor(upId, m_zonalDir * 2 + 1,
false) && !upStream().a_isHalo(upId)) {
218 const MInt parentId = upStream().c_parentId(upId);
219 if(parentId > -1 && !upStream().a_hasNeighbor(parentId, m_zonalDir * 2 + 1,
false)) {
223 const MInt downId = up2downId(upId, lastLayer);
225 m_downUp.push_back(make_pair(downId, upId));
229 }
else if(m_zonalMethod ==
"B") {
231 m_downStreamOffset = m_downUp.size();
234 if(downStream().isActive()) {
235 if(m_zonalMethod ==
"P") {
238 for(
MInt downId = 0; downId < downStream().c_noCells(); downId++) {
239 if(downStream().a_coordinate(downId, m_zonalDir) < m_zonalCoordinate) {
240 MBool lastLayer =
false;
241 if(!downStream().a_hasNeighbor(downId, m_zonalDir * 2,
false) && !downStream().a_isHalo(downId)) {
242 const MInt parentId = downStream().c_parentId(downId);
243 if(parentId > -1 && !downStream().a_hasNeighbor(parentId, m_zonalDir * 2,
false)) {
247 const MInt upId = down2upId(downId, lastLayer);
249 m_upDown.push_back(make_pair(upId, downId));
253 }
else if(m_zonalMethod ==
"B") {
255 m_upStreamOffset = m_upDown.size();
265template <MInt nDim,
class SysEqn>
270 m_upDown.resize(m_upStreamOffset);
271 m_downUp.resize(m_downStreamOffset);
274 if(upStream().isActive()) {
275 if(m_zonalMethod ==
"P") {
276 for(
MInt upId = upStream().c_noCells(); upId < upStream().a_noCells(); upId++) {
277 if(upStream().a_coordinate(upId, m_zonalDir) > m_zonalCoordinate) {
278 MBool lastLayer =
false;
279 const MInt associatedId = upStream().getAssociatedInternalCell(upId);
280 if(!upStream().a_hasNeighbor(associatedId, m_zonalDir * 2 + 1,
false) && !upStream().a_isHalo(associatedId)) {
281 const MInt parentId = upStream().c_parentId(associatedId);
282 if(parentId > -1 && !upStream().a_hasNeighbor(parentId, m_zonalDir * 2 + 1,
false)) {
286 const MInt downId = up2downId(upId, lastLayer);
288 m_upDown.push_back(make_pair(upId, downId));
292 }
else if(m_zonalMethod ==
"B") {
297 if(downStream().isActive()) {
298 if(m_zonalMethod ==
"P") {
299 for(
MInt downId = downStream().c_noCells(); downId < downStream().a_noCells(); downId++) {
300 if(downStream().a_coordinate(downId, m_zonalDir) < m_zonalCoordinate) {
301 MBool lastLayer =
false;
302 const MInt associatedId = downStream().getAssociatedInternalCell(downId);
303 if(!downStream().a_hasNeighbor(associatedId, m_zonalDir * 2,
false) && !downStream().a_isHalo(associatedId)) {
304 const MInt parentId = downStream().c_parentId(associatedId);
305 if(parentId > -1 && !downStream().a_hasNeighbor(parentId, m_zonalDir * 2,
false)) {
309 const MInt upId = down2upId(downId, lastLayer);
311 m_upDown.push_back(make_pair(downId, upId));
315 }
else if(m_zonalMethod ==
"B") {
325template <MInt nDim,
class SysEqn>
329 if(m_upDown.empty()) {
330 ASSERT(m_downUp.empty(),
"");
335 if(solverId == m_upStreamId || solverId == -1) {
336 for(
auto it = m_upDown.begin(); it != m_upDown.end(); it++) {
337 const MInt upId = it->first;
338 const MInt downId = it->second;
340 for(
MInt var = 0; var < upStream().m_sysEqn.CV->noVariables; var++) {
341 downStream().a_variable(downId, var) = upStream().a_variable(upId, var);
342 downStream().a_pvariable(downId, var) = upStream().a_pvariable(upId, var);
348 if(solverId == m_downStreamId || solverId == -1) {
349 for(
auto it = m_downUp.begin(); it != m_downUp.end(); it++) {
350 const MInt downId = it->first;
351 const MInt upId = it->second;
353 for(
MInt var = 0; var < downStream().m_sysEqn.CV->noVariables; var++) {
354 upStream().a_variable(upId, var) = downStream().a_variable(downId, var);
355 upStream().a_pvariable(upId, var) = downStream().a_pvariable(downId, var);
366template <MInt nDim,
class SysEqn>
370 if(!downStream().isActive())
return -1;
376 if(upCell >= upStream().c_noCells()) {
377 const MInt gridCell = upStream().getAssociatedInternalCell(upCell);
378 if(upStream().a_isBndryGhostCell(upCell)) {
380 const MInt bndryId = upStream().a_bndryId(gridCell);
382 for(
MInt surf = 0; surf < upStream().m_bndryCells->a[bndryId].m_noSrfcs; surf++) {
383 if(upStream().m_bndryCells->a[bndryId].m_srfcVariables[surf]->m_ghostCellId == upCell) {
388 ASSERT(srfc >= 0,
"");
397 upStream().assertValidGridCellId(upCell);
399 const MInt gridId = upStream().grid().tree().solver2grid(upCell);
400 ASSERT(upStream().grid().solverFlag(gridId, m_upStreamId),
"");
402 if(!downStream().grid().solverFlag(gridId, m_downStreamId))
return -1;
404 MInt downId = downStream().grid().tree().grid2solver(gridId);
407 ASSERT(downStream().a_level(downId) == upStream().a_level(upCell),
"");
410 if(cellType == 1 || downId < 0)
return downId;
413 ASSERT(downStream().a_isBndryCell(upCell),
"");
420 const MInt srfc = -cellType;
421 const MInt bndryId = downStream().a_bndryId(downId);
422 downId = downStream().m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_ghostCellId;
427 mTerm(1, AT_,
"Not yet implemented for splitchilds");
437template <MInt nDim,
class SysEqn>
441 if(!upStream().isActive())
return -1;
447 if(downCell >= downStream().c_noCells()) {
448 const MInt gridCell = downStream().getAssociatedInternalCell(downCell);
449 if(downStream().a_isBndryGhostCell(downCell)) {
451 const MInt bndryId = downStream().a_bndryId(gridCell);
453 for(
MInt surf = 0; surf < downStream().m_bndryCells->a[bndryId].m_noSrfcs; surf++) {
454 if(downStream().m_bndryCells->a[bndryId].m_srfcVariables[surf]->m_ghostCellId == downCell) {
459 ASSERT(srfc >= 0,
"");
468 downStream().assertValidGridCellId(downCell);
470 const MInt gridId = downStream().grid().tree().solver2grid(downCell);
471 ASSERT(downStream().grid().solverFlag(gridId, m_downStreamId),
"");
473 if(!upStream().grid().solverFlag(gridId, m_upStreamId))
return -1;
475 MInt upCell = upStream().grid().tree().grid2solver(gridId);
478 ASSERT(downStream().a_level(downCell) == upStream().a_level(upCell),
"");
481 if(cellType == 1 || upCell < 0)
return upCell;
484 ASSERT(upStream().a_isBndryCell(upCell),
"");
491 const MInt srfc = -cellType;
492 const MInt bndryId = upStream().a_bndryId(upCell);
493 upCell = upStream().m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_ghostCellId;
498 mTerm(1, AT_,
"Not yet implemented for splitchilds");
508template <MInt nDim,
class SysEqn>
510 const MFloat invalidTimeStep = std::numeric_limits<MFloat>::max();
511 MFloat timeUp = invalidTimeStep;
512 MFloat timeDown = invalidTimeStep;
513 MInt maxLevelUp = -1;
514 MInt maxLevelDown = -1;
515 MFloat newTimeUp = invalidTimeStep;
516 MFloat newTimeDown = invalidTimeStep;
519 if(upStream().isActive() && downStream().isActive()) {
520 timeUp = upStream().timeStep(
true);
521 maxLevelUp = upStream().maxLevel();
522 timeDown = downStream().timeStep(
true);
523 maxLevelDown = downStream().maxLevel();
525 MInt levelDiff = maxLevelDown - maxLevelUp;
527 newTimeUp =
mMin(timeUp, timeDown);
528 newTimeDown = newTimeUp;
530 ASSERT(m_zonalDualTimeStepping,
"");
533 newTimeDown =
mMin(newTimeDown, newTimeUp / 2.0);
534 newTimeUp = 2.0 * newTimeDown;
535 }
else if(levelDiff == -1) {
537 newTimeUp =
mMin(newTimeUp, newTimeDown / 2.0);
538 newTimeDown = 2.0 * newTimeUp;
540 mTerm(1, AT_,
"Zonal dual-timeStepping currently only implemented for 1 level difference!");
545 if(downStream().isActive()) {
546 MPI_Allreduce(MPI_IN_PLACE, &newTimeDown, 1, MPI_DOUBLE, MPI_MIN, downStream().mpiComm(), AT_,
"MPI_IN_PLACE",
549 if(upStream().isActive()) {
550 MPI_Allreduce(MPI_IN_PLACE, &newTimeUp, 1, MPI_DOUBLE, MPI_MIN, upStream().mpiComm(), AT_,
"MPI_IN_PLACE",
554 if(upStream().isActive()) {
555 upStream().forceTimeStep(newTimeUp);
557 if(downStream().isActive()) {
558 downStream().forceTimeStep(newTimeDown);
void unifyTimeStep()
set the same timeStep both FvMb-solvers
void readProperties() override
void finalizeBalance(const MInt) override
update zonal mapping after balance
CouplerFvMbZonal(const MInt couplingId, FvMbSolver *upStream, FvMbSolver *downStream)
void preCouple(MInt) override
exchange zonal variables before each runge-Kutta Step
FvMbSolver & upStream() const
void exchangeZonalValues(const MInt)
exchange zonal variables around the zonal coordinate from upstream to downstream solver and the other...
void postCouple(MInt) override
unify the time-Step
MInt up2downId(MInt, const MBool)
conversion from upStream solverId to the downStream solverId NOTE: also handles bndry-ghost cell conv...
void subCouple(MInt, MInt, std::vector< MBool > &)
exchange zonal variables each runge-Kutta Step
void finalizeAdaptation(const MInt) override
update zonal mapping after adaptation
MInt down2upId(MInt, const MBool)
conversion from downStream to upStream cellId NOTE: also handles bndry-ghost cells
void createZonalMapping()
create the cell mapping which allows for a faster exchange during each RK-Step. This requires little ...
FvMbSolver * m_solverDown
void finalizeCouplerInit()
create first zonal mapping for the zonal exchange
void updateZonalMapping()
update the zonal mapping before the FVMb-timeStep as the bndryCell order might have changed!...
FvMbSolver & downStream() const
const MInt m_solverId
a unique solver identifier
void mTerm(const MInt errorCode, const MString &location, const MString &message)
constexpr T mMin(const T &x, const T &y)
@ IsSplitChild
cell is a split child
@ IsSplitClone
cell is an older-version of a splitchild
int MPI_Allreduce(const void *sendbuf, void *recvbuf, int count, MPI_Datatype datatype, MPI_Op op, MPI_Comm comm, const MString &name, const MString &sndvarname, const MString &rcvvarname)
same as MPI_Allreduce