MAIA bb96820c
Multiphysics at AIA
Loading...
Searching...
No Matches
fvmbzonal.cpp
Go to the documentation of this file.
1// Copyright (C) 2024 The m-AIA AUTHORS
2//
3// This file is part of m-AIA (https://git.rwth-aachen.de/aia/m-AIA/m-AIA)
4//
5// SPDX-License-Identifier: LGPL-3.0-only
6
7#include "fvmbzonal.h"
8
9#include <algorithm>
10#include <cmath>
11#include <stack>
12#include <vector>
14#include "MEMORY/alloc.h"
15#include "MEMORY/scratch.h"
16#include "globals.h"
17#include "globalvariables.h"
18
19using namespace std;
20
21
22template <MInt nDim, class SysEqn>
24 : Coupling(couplingId), CouplingFvMb<nDim, SysEqn>(couplingId, upStream_) {
25 TRACE();
26
27 // set solver pointer and ids
28 m_solverUp = upStream_;
29 m_solverDown = downStream_;
30 m_couplingId = couplingId;
31
34
36}
37
41template <MInt nDim, class SysEqn>
43 m_noRKSteps = 5;
44 m_noRKSteps = Context::getSolverProperty<MInt>("noRKSteps", upStream().solverId(), AT_, &m_noRKSteps);
45
46 ASSERT(m_noRKSteps == Context::getSolverProperty<MInt>("noRKSteps", downStream().solverId(), AT_, &m_noRKSteps), "");
47 m_zonalMethod = "";
61 m_zonalMethod = Context::getSolverProperty<MString>("zonalMethod", couplerId(), AT_, &m_zonalMethod);
69 m_zonalDualTimeStepping =
70 Context::getSolverProperty<MBool>("zonalDualTimeStepping", couplerId(), AT_, &m_zonalDualTimeStepping);
71
72 if(m_zonalMethod == "P") {
82 m_zonalCoordinate = Context::getSolverProperty<MFloat>("zonalCoordinate", couplerId(), AT_);
83
95 m_zonalDir = Context::getSolverProperty<MInt>("zonalDir", couplerId(), AT_);
96
97 if(upStream().domainId() == 0) {
98 cerr << "Using cartesian zonal Method with plane-cut at " << m_zonalCoordinate << " in direction " << m_zonalDir
99 << endl;
100 }
101
102 } else if(m_zonalMethod == "B") {
103 } else {
104 mTerm(1, AT_, "ZonalMethod not implemented yet!");
105 }
106}
107
108
112template <MInt nDim, class SysEqn>
114 createZonalMapping();
115
116 ASSERT(upStream().a_timeStepComputationInterval() == downStream().a_timeStepComputationInterval(), "");
117}
118
122template <MInt nDim, class SysEqn>
124 if(solverLoopId >= m_upStreamId && solverLoopId >= m_downStreamId) {
125 createZonalMapping();
126 unifyTimeStep();
127 }
128}
129
133template <MInt nDim, class SysEqn>
135 if(solverLoopId >= m_upStreamId && solverLoopId >= m_downStreamId) {
136 createZonalMapping();
137 }
138}
139
143template <MInt nDim, class SysEqn>
145 std::vector<MBool>& /*solverCompleted*/) {
146 // only during FVMb computation
147 if(recipeStep == 1 && (solverId == m_upStreamId || solverId == m_downStreamId)) {
148 m_RKStep++;
149
150 if(m_RKStep == 2 * m_noRKSteps) {
151 // complete exchange during the last runge-Kutta Step
152 exchangeZonalValues(-1);
153 } else {
154 // only update from the solver who just made its timeStep!
155 exchangeZonalValues(solverId);
156 }
157
158 // check the timeStep contraint at the last-RK-step of both solvers
159 // if the timeStep might have changed!
160 if(m_RKStep == 2 * m_noRKSteps && upStream().a_timeStepComputationInterval() > 0
161 && globalTimeStep % upStream().a_timeStepComputationInterval() == 0) {
162 unifyTimeStep();
163 }
164 }
165}
166
170template <MInt nDim, class SysEqn>
172 // past the LS-solver
173 // before the FvMb-solver
174 if(solverStep == 1) {
175 // updateZonalMapping();
176 exchangeZonalValues(-1);
177 m_RKStep = 0;
178 }
179}
180
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!.");
192 }
193 }
194}
195
200template <MInt nDim, class SysEqn>
202 TRACE();
203
204 m_upDown.clear();
205 m_downUp.clear();
206
207 m_upStreamOffset = 0;
208 m_downStreamOffset = 0;
209
210 if(upStream().isActive()) {
211 if(m_zonalMethod == "P") {
212 // first create mapping for valid grid cells
213 // this mapping will only change duing adaptation or balance
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)) {
220 lastLayer = true;
221 }
222 }
223 const MInt downId = up2downId(upId, lastLayer);
224 if(downId > -1) {
225 m_downUp.push_back(make_pair(downId, upId));
226 }
227 }
228 }
229 } else if(m_zonalMethod == "B") {
230 }
231 m_downStreamOffset = m_downUp.size();
232 }
233
234 if(downStream().isActive()) {
235 if(m_zonalMethod == "P") {
236 // first create mapping for valid grid cells
237 // this mapping will only change duing adaptation or balance
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)) {
244 lastLayer = true;
245 }
246 }
247 const MInt upId = down2upId(downId, lastLayer);
248 if(upId > -1) {
249 m_upDown.push_back(make_pair(upId, downId));
250 }
251 }
252 }
253 } else if(m_zonalMethod == "B") {
254 }
255 m_upStreamOffset = m_upDown.size();
256 }
257}
258
265template <MInt nDim, class SysEqn>
267 TRACE();
268
269 // resize to grid-cell offset
270 m_upDown.resize(m_upStreamOffset);
271 m_downUp.resize(m_downStreamOffset);
272
273 // re-build bndryCell mapping
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)) {
283 lastLayer = true;
284 }
285 }
286 const MInt downId = up2downId(upId, lastLayer);
287 if(downId > -1) {
288 m_upDown.push_back(make_pair(upId, downId));
289 }
290 }
291 }
292 } else if(m_zonalMethod == "B") {
293 }
294 }
295
296
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)) {
306 lastLayer = true;
307 }
308 }
309 const MInt upId = down2upId(downId, lastLayer);
310 if(upId > -1) {
311 m_upDown.push_back(make_pair(downId, upId));
312 }
313 }
314 }
315 } else if(m_zonalMethod == "B") {
316 }
317 }
318}
319
320
325template <MInt nDim, class SysEqn>
327 TRACE();
328
329 if(m_upDown.empty()) {
330 ASSERT(m_downUp.empty(), "");
331 return;
332 }
333
334 // transfer data from up-stream to down-stream
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;
339
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);
343 }
344 }
345 }
346
347 // transfer data from down-stream to up-stream
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;
352
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);
356 }
357 }
358 }
359}
360
361
366template <MInt nDim, class SysEqn>
368 TRACE();
369
370 if(!downStream().isActive()) return -1;
371
372 // to hanlde bndry ghostCells and others as well
373 // 1: regular grid cell
374 // < 1: bndry-ghost cell (index represents matching surface)
375 MInt cellType = 1;
376 if(upCell >= upStream().c_noCells()) {
377 const MInt gridCell = upStream().getAssociatedInternalCell(upCell);
378 if(upStream().a_isBndryGhostCell(upCell)) {
379 // find the matching surface of the grid cell to which the upCell is the bndry-ghostcell
380 const MInt bndryId = upStream().a_bndryId(gridCell);
381 MInt srfc = -1;
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) {
384 srfc = surf;
385 break;
386 }
387 }
388 ASSERT(srfc >= 0, "");
389 cellType = -srfc;
390 } else if(upStream().a_hasProperty(upCell, FvCell::IsSplitChild)
391 || upStream().a_hasProperty(upCell, FvCell::IsSplitClone)) {
392 cellType = 2;
393 }
394 upCell = gridCell;
395 }
396
397 upStream().assertValidGridCellId(upCell);
398
399 const MInt gridId = upStream().grid().tree().solver2grid(upCell);
400 ASSERT(upStream().grid().solverFlag(gridId, m_upStreamId), "");
401
402 if(!downStream().grid().solverFlag(gridId, m_downStreamId)) return -1;
403
404 MInt downId = downStream().grid().tree().grid2solver(gridId);
405
406 if(downId > 0) {
407 ASSERT(downStream().a_level(downId) == upStream().a_level(upCell), "");
408 }
409
410 if(cellType == 1 || downId < 0) return downId;
411
412 if(!lastLayer) {
413 ASSERT(downStream().a_isBndryCell(upCell), "");
414 } else {
415 return -1;
416 }
417
418 if(cellType < 1) {
419 // bndry-ghost cell
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;
423 return downId;
424
425 } else {
426 // split child
427 mTerm(1, AT_, "Not yet implemented for splitchilds");
428 }
429
430 return -1;
431}
432
437template <MInt nDim, class SysEqn>
439 TRACE();
440
441 if(!upStream().isActive()) return -1;
442
443 // to hanlde bndry ghostCells and others as well
444 // 1: regular grid cell
445 // < 1: bndry-ghost cell (index represents matching surface)
446 MInt cellType = 1;
447 if(downCell >= downStream().c_noCells()) {
448 const MInt gridCell = downStream().getAssociatedInternalCell(downCell);
449 if(downStream().a_isBndryGhostCell(downCell)) {
450 // find the matching surface of the grid cell to which the upCell is the bndry-ghostcell
451 const MInt bndryId = downStream().a_bndryId(gridCell);
452 MInt srfc = -1;
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) {
455 srfc = surf;
456 break;
457 }
458 }
459 ASSERT(srfc >= 0, "");
460 cellType = -srfc;
461 } else if(downStream().a_hasProperty(downCell, FvCell::IsSplitChild)
462 || downStream().a_hasProperty(downCell, FvCell::IsSplitClone)) {
463 cellType = 2;
464 }
465 downCell = gridCell;
466 }
467
468 downStream().assertValidGridCellId(downCell);
469
470 const MInt gridId = downStream().grid().tree().solver2grid(downCell);
471 ASSERT(downStream().grid().solverFlag(gridId, m_downStreamId), "");
472
473 if(!upStream().grid().solverFlag(gridId, m_upStreamId)) return -1;
474
475 MInt upCell = upStream().grid().tree().grid2solver(gridId);
476
477 if(upCell > 0) {
478 ASSERT(downStream().a_level(downCell) == upStream().a_level(upCell), "");
479 }
480
481 if(cellType == 1 || upCell < 0) return upCell;
482
483 if(!lastLayer) {
484 ASSERT(upStream().a_isBndryCell(upCell), "");
485 } else {
486 return -1;
487 }
488
489 if(cellType < 1) {
490 // bndry-ghost cell
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;
494 return upCell;
495
496 } else {
497 // split child
498 mTerm(1, AT_, "Not yet implemented for splitchilds");
499 }
500
501 return -1;
502}
503
504
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;
517
518 // determine the new timeStep on ranks which have both up-Stream and downStream solvers!
519 if(upStream().isActive() && downStream().isActive()) {
520 timeUp = upStream().timeStep(true);
521 maxLevelUp = upStream().maxLevel();
522 timeDown = downStream().timeStep(true);
523 maxLevelDown = downStream().maxLevel();
524
525 MInt levelDiff = maxLevelDown - maxLevelUp;
526 if(levelDiff == 0) {
527 newTimeUp = mMin(timeUp, timeDown);
528 newTimeDown = newTimeUp;
529 } else {
530 ASSERT(m_zonalDualTimeStepping, "");
531 if(levelDiff == 1) {
532 // downStream has higher level => lower timeStep!
533 newTimeDown = mMin(newTimeDown, newTimeUp / 2.0);
534 newTimeUp = 2.0 * newTimeDown;
535 } else if(levelDiff == -1) {
536 // upStream has the higher level => lower timeStep!
537 newTimeUp = mMin(newTimeUp, newTimeDown / 2.0);
538 newTimeDown = 2.0 * newTimeUp;
539 } else {
540 mTerm(1, AT_, "Zonal dual-timeStepping currently only implemented for 1 level difference!");
541 }
542 }
543 }
544
545 if(downStream().isActive()) {
546 MPI_Allreduce(MPI_IN_PLACE, &newTimeDown, 1, MPI_DOUBLE, MPI_MIN, downStream().mpiComm(), AT_, "MPI_IN_PLACE",
547 "newTimeDown");
548 }
549 if(upStream().isActive()) {
550 MPI_Allreduce(MPI_IN_PLACE, &newTimeUp, 1, MPI_DOUBLE, MPI_MIN, upStream().mpiComm(), AT_, "MPI_IN_PLACE",
551 "newTimeUp");
552 }
553
554 if(upStream().isActive()) {
555 upStream().forceTimeStep(newTimeUp);
556 }
557 if(downStream().isActive()) {
558 downStream().forceTimeStep(newTimeDown);
559 }
560}
561
562// Explicit template instantiations
MInt m_downStreamId
Definition: fvmbzonal.h:66
void unifyTimeStep()
set the same timeStep both FvMb-solvers
Definition: fvmbzonal.cpp:509
void readProperties() override
void finalizeBalance(const MInt) override
update zonal mapping after balance
Definition: fvmbzonal.cpp:134
CouplerFvMbZonal(const MInt couplingId, FvMbSolver *upStream, FvMbSolver *downStream)
Definition: fvmbzonal.cpp:23
void preCouple(MInt) override
exchange zonal variables before each runge-Kutta Step
Definition: fvmbzonal.cpp:171
FvMbSolver & upStream() const
Definition: fvmbzonal.h:58
void exchangeZonalValues(const MInt)
exchange zonal variables around the zonal coordinate from upstream to downstream solver and the other...
Definition: fvmbzonal.cpp:326
void postCouple(MInt) override
unify the time-Step
Definition: fvmbzonal.cpp:185
MInt up2downId(MInt, const MBool)
conversion from upStream solverId to the downStream solverId NOTE: also handles bndry-ghost cell conv...
Definition: fvmbzonal.cpp:367
void subCouple(MInt, MInt, std::vector< MBool > &)
exchange zonal variables each runge-Kutta Step
Definition: fvmbzonal.cpp:144
FvMbSolver * m_solverUp
Definition: fvmbzonal.h:62
void finalizeAdaptation(const MInt) override
update zonal mapping after adaptation
Definition: fvmbzonal.cpp:123
MInt down2upId(MInt, const MBool)
conversion from downStream to upStream cellId NOTE: also handles bndry-ghost cells
Definition: fvmbzonal.cpp:438
void createZonalMapping()
create the cell mapping which allows for a faster exchange during each RK-Step. This requires little ...
Definition: fvmbzonal.cpp:201
FvMbSolver * m_solverDown
Definition: fvmbzonal.h:63
void finalizeCouplerInit()
create first zonal mapping for the zonal exchange
Definition: fvmbzonal.cpp:113
void updateZonalMapping()
update the zonal mapping before the FVMb-timeStep as the bndryCell order might have changed!...
Definition: fvmbzonal.cpp:266
FvMbSolver & downStream() const
Definition: fvmbzonal.h:59
const MInt m_solverId
a unique solver identifier
Definition: solver.h:90
void mTerm(const MInt errorCode, const MString &location, const MString &message)
Definition: functions.cpp:29
constexpr T mMin(const T &x, const T &y)
Definition: functions.h:90
@ IsSplitChild
cell is a split child
@ IsSplitClone
cell is an older-version of a splitchild
MInt globalTimeStep
int32_t MInt
Definition: maiatypes.h:62
double MFloat
Definition: maiatypes.h:52
bool MBool
Definition: maiatypes.h:58
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