MAIA bb96820c
Multiphysics at AIA
Loading...
Searching...
No Matches
couplerfvmultilevel.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
8
9#include <cmath>
11#include "MEMORY/scratch.h"
12
13using namespace std;
14
19template <MInt nDim, class SysEqn>
21 const MInt couplingId, std::vector<FvCartesianSolverXD<nDim, SysEqn>*> solvers)
22 : Base(couplingId), BaseFv(couplingId, solvers, solvers.size()) {
23 TRACE();
24
25 // Initialize timers
26 initTimers();
27}
28
29
30template <MInt nDim, class SysEqn>
32 TRACE();
33
34 // Stop coupler timer
35 RECORD_TIMER_STOP(timer("Total"));
36}
37
38
40template <MInt nDim, class SysEqn>
42 TRACE();
43
59 m_prolongationMethod = 0;
60 m_prolongationMethod = Context::getBasicProperty("prolongationMethod", AT_, &m_prolongationMethod);
61
62 m_log << "Multilevel calculate gradients: " << m_prolongationMethod << std::endl;
75 m_correctCoarseBndry = false;
76 m_correctCoarseBndry = Context::getBasicProperty("correctCoarseBndry", AT_, &m_correctCoarseBndry);
77
78 // Mark solver 0 as primary multilevel solver
79 fvSolver(0).setMultilevelPrimary();
80
81 initRestrictedCells();
82
83 initMapping();
84
85 initLeafCells();
86
87 resetMultiLevelVariables();
88
89 if(!fvSolver(0).m_adaptation || (globalTimeStep > 0 && !fvSolver(0).m_levelSetMb)) {
90 resetSecondaryFlowVariables();
91 }
92
93 // Perform checks
94 sanityCheck(0);
95}
96
98template <MInt nDim, class SysEqn>
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
121 initSplitMapping();
122}
123
125template <MInt nDim, class SysEqn>
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
136 initRestrictedCells();
137
138 initMapping();
139
140 initLeafCells();
141
142 if(globalTimeStep < 0) {
143 resetMultiLevelVariables();
144
145 resetSecondaryFlowVariables();
146 }
147 }
148}
149
150
151template <MInt nDim, class SysEqn>
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++) {
159 correctCoarseBndryCells(solver);
160 }
161 }
162 }
163
164 if(fvSolver(0).m_reComputedBndry || globalTimeStep == fvSolver(0).m_restartTimeStep) {
165 initSplitMapping();
166 }
167}
168
169template <MInt nDim, class SysEqn>
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}
197
198
200template <MInt nDim, class SysEqn>
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}
259
260
262template <MInt nDim, class SysEqn>
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}
277
278
280template <MInt nDim, class SysEqn>
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}
433
434
436template <MInt nDim, class SysEqn>
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}
455
456
458template <MInt nDim, class SysEqn>
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}
488
489
491template <MInt nDim, class SysEqn>
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}
546
547
549template <MInt nDim, class SysEqn>
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}
742
743
745template <MInt nDim, class SysEqn>
747 TRACE();
748
749 m_restrictedCells.resize(noSolvers());
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}
770
771
773template <MInt nDim, class SysEqn>
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}
801
804template <MInt nDim, class SysEqn>
806 TRACE();
807
808 m_splitCellMapping.clear();
809 m_splitCellMapping.resize(noSolvers());
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}
870template <MInt nDim, class SysEqn>
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}
898
900template <MInt nDim, class SysEqn>
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}
921
924template <MInt nDim, class SysEqn>
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}
949
960template <MInt nDim, class SysEqn>
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}
1119
1120
1127template <MInt nDim, class SysEqn>
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}
1217
1218
1225template <MInt nDim, class SysEqn>
1227 if(m_timers.count(name) == 0) {
1228 TERMM(1, "Timer '" + name + "' does not exist.");
1229 }
1230 return m_timers.at(name);
1231}
1232
1233
1234template <MInt nDim, class SysEqn>
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}
1249
1250
1251template <MInt nDim, class SysEqn>
1253 if(name.empty()) {
1254 TERMM(1, "Empty timer name");
1255 }
1256 RECORD_TIMER_START(timer(name));
1257 return true;
1258}
1259
1260
1261template <MInt nDim, class SysEqn>
1263 if(name.empty()) {
1264 TERMM(1, "Empty timer name");
1265 }
1266 RECORD_TIMER_STOP(timer(name));
1267 return true;
1268}
1269
1270
1271template <MInt nDim, class SysEqn>
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}
1307
1308
1310template <MInt nDim, class SysEqn>
1312 const MInt couplingId, std::vector<FvCartesianSolverXD<nDim, SysEqn>*> solvers)
1313 : Base(couplingId), BaseCoupler(couplingId, solvers) {
1314 TRACE();
1315}
1316
1317
1319template <MInt nDim, class SysEqn>
1321 TRACE();
1322 startTimer("Main");
1323
1324 for(MInt solverId = 0; solverId < noSolvers(); solverId++) {
1325 if(fvSolver(solverId).getSolverStatus()) {
1326 TERMM(1, "Multilevel interpolation postCouple(): found active solver/level - all solvers should be inactive!");
1327 }
1328 }
1329
1330 // Reset solution unless for the coarsest level with the actual restart data
1331 for(MInt i = 0; i < noSolvers() - 1; i++) {
1332 reset(i); // Resets also the restricted variables for the next coarser level
1333 }
1334
1335 // Prolong the coarse level restart data to the finest level (since the restricted vars and the stored slopes are set
1336 // to 0 above the full solution is transferred to the next finer level)
1337 for(MInt i = noSolvers() - 1; i > 0; i--) {
1338 prolongation(i);
1339 }
1340
1341 stopTimer("Main");
1342}
1343
1344
1346template <MInt nDim, class SysEqn>
1348 TRACE();
1349
1350 auto& fine = fvSolver(level);
1351 auto& coarse = fvSolver(level + 1);
1352 const MInt noVars = fine.CV->noVariables;
1353
1354 for(MInt cellId = 0; cellId < fine.noInternalCells(); cellId++) {
1355 for(MInt varId = 0; varId < noVars; varId++) {
1356 // Reset variables on this level
1357 fine.a_variable(cellId, varId) = 0.0;
1358 for(MInt dim = 0; dim < nDim; dim++) {
1359 // ... and slopes (of conservative variables)
1360 fine.a_storedSlope(cellId, varId, dim) = 0.0;
1361 }
1362 }
1363 }
1364
1365 for(MInt cellId = 0; cellId < coarse.noInternalCells(); cellId++) {
1366 for(MInt varId = 0; varId < noVars; varId++) {
1367 // Reset restricted variables on next coarser level
1368 coarse.a_restrictedVar(cellId, varId) = 0.0;
1369 for(MInt dim = 0; dim < nDim; dim++) {
1370 // ... and slopes (of conservative variables)
1371 coarse.a_storedSlope(cellId, varId, dim) = 0.0;
1372 }
1373 }
1374 }
1375}
1376
1377
1378// Explicit template instantiations
1387
static T getBasicProperty(const MString name, const MString &nameOfCallingFunction, const T *default_value, MInt pos=0)
Definition: context.h:149
void correctCoarseBndryCells(const MInt solverId)
MInt timer(const MString &name)
void initRestrictedCells()
for each solver that will be restricted (all except the coarsest), store restricted cells
void finalizeCouplerInit()
call after the initial adaptation when all cells are refined correctly
MBool stopTimer(const MString &name)
void postCouple(MInt) override
void initLeafCells()
store internal leaf cells for each solver except for finest solver, for which they are not needed
void restrictData(const MInt level)
Restrict the data (fine-coarse) on the given level.
void resetSecondaryFlowVariables()
for each solver except the finest, reset variables to NaN to ensure that only restricted information ...
void prolongation(const MInt level)
Prolong the solution on the given coarse level onto the next finer level.
void storeRestrictedVariables(const MInt level)
Store the restricted variables (required for the prolongation)
typename BaseFv::solverType SolverType
CouplerFvMultilevel(const MInt couplingId, std::vector< FvCartesianSolverXD< nDim, SysEqn > * > solvers)
void prolongData(const MInt level)
Prolong the data of a coarse level.
void finalizeAdaptation(MInt solverId)
call after the initial adaptation when all cells are refined correctly
void initSplitMapping()
for each coarse solver, store cell map of split-cells to next finer solver childs
void initMapping()
for each coarse solver, store cell map to next finer solver
MInt & createTimer(const MString &name)
void preCouple(MInt) override
void computeCoarseLevelCorrection(const MInt level)
Compute the coarse level correction tau.
void resetTau(const MInt level)
Reset the coarse level correction tau.
MBool startTimer(const MString &name)
void resetMultiLevelVariables()
for each solver, reset multilevel variables
void init() override
void restriction(const MInt level)
Restrict the solution on the given fine level onto the next coarser level.
FV multilevel interpolation coupler to transfer solution data of a coarse grid onto a finer grid.
typename BaseCoupler::Base Base
void postCouple(MInt) override
Coupling routine to transfer coarse level restart data to the finest level/solver.
void reset(const MInt level)
Reset variables/slopes of a level/solver.
CouplerFvMultilevelInterpolation(const MInt couplingId, std::vector< FvCartesianSolverXD< nDim, SysEqn > * > solvers)
Constructor for multilevel interpolation coupler.
This class is a ScratchSpace.
Definition: scratch.h:758
size_type size() const
Definition: scratch.h:302
pointer data()
Definition: scratch.h:289
iterator end()
Definition: scratch.h:281
iterator begin()
Definition: scratch.h:273
void mTerm(const MInt errorCode, const MString &location, const MString &message)
Definition: functions.cpp:29
constexpr Real POW2(const Real x)
Definition: functions.h:119
MInt globalTimeStep
InfoOutFile m_log
constexpr MLong IPOW2(MInt x)
int32_t MInt
Definition: maiatypes.h:62
std::basic_string< char > MString
Definition: maiatypes.h:55
MInt noSolvers
Definition: maiatypes.h:73
double MFloat
Definition: maiatypes.h:52
MInt * solvers
Definition: maiatypes.h:72
bool MBool
Definition: maiatypes.h:58
MInt id
Definition: maiatypes.h:71
MFloat dist(const Point< DIM > &p, const Point< DIM > &q)
Definition: pointbox.h:54