MAIA bb96820c
Multiphysics at AIA
Loading...
Searching...
No Matches
application.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 "application.h"
8
9#include <chrono>
10
11#if not defined(MAIA_DISABLE_DG)
16#endif
17
18#include "ACA/acasolver.h"
19#include "COMM/mpioverride.h"
21#include "COUPLER/couplerlbfv.h"
23#include "COUPLER/couplerlblb.h"
25#include "COUPLER/fvmbzonal.h"
26#include "COUPLER/fvparticle.h"
27#include "COUPLER/fvzonalrtv.h"
28#include "COUPLER/fvzonalstg.h"
29#include "COUPLER/lbdgape.h"
30#include "COUPLER/lblpt.h"
31#include "COUPLER/lbrb.h"
32#include "COUPLER/lsfv.h"
34#include "COUPLER/lsfvmb.h"
35#include "COUPLER/lslb.h"
36#include "COUPLER/lslbsurface.h"
37#include "FC/fcsolver.h"
45#ifndef MAIA_DISABLE_STRUCTURED
48#endif
51#include "IO/parallelio.h"
52#include "LB/lbsolverdxqy.h"
53#include "LB/lbsolverfactory.h"
54#include "LPT/lpt.h"
57#include "POST/postdata.h"
58#include "POST/postprocessing.h"
66#include "RB/rigidbodies.h"
67#include "executionrecipe.h"
68
69using namespace std;
70using namespace maia;
71
72// TODO labels:toenhance move these to solvertraits.h to allow usage in other places (e.g. in the coupling
73// conditions)
74namespace {
75
76// Auxiliary type traits to support selecting the correct FV-APE solver class
77template <MInt nDim>
78struct FvApeSolverXD {};
79template <>
80struct FvApeSolverXD<2> {
81 using type = FvApeSolver2D;
82};
83template <>
84struct FvApeSolverXD<3> {
85 using type = FvApeSolver3D;
86};
87
88// Auxiliary type traits to support selecting the correct structured solver class
89#ifndef MAIA_DISABLE_STRUCTURED
90template <MInt nDim>
91struct FvStructuredSolverXD {};
92template <>
93struct FvStructuredSolverXD<2> {
94 using type = FvStructuredSolver2D;
95};
96template <>
97struct FvStructuredSolverXD<3> {
98 using type = FvStructuredSolver3D;
99};
100#endif
101
102// Auxiliary type traits to support selecting the correct LS solver class
103template <MInt nDim>
104struct LsCartesianSolverXD {};
105template <>
106struct LsCartesianSolverXD<2> {
107 using type = LsCartesianSolver<2>;
108};
109template <>
110struct LsCartesianSolverXD<3> {
111 using type = LsCartesianSolver<3>;
112};
113
114template <MInt nDim, class SysEqn>
115struct LsFvCombustionXD {};
116template <>
117struct LsFvCombustionXD<2, FvSysEqnNS<2>> {
119};
120template <>
121struct LsFvCombustionXD<3, FvSysEqnNS<3>> {
123};
124template <>
125struct LsFvCombustionXD<2, FvSysEqnRANS<2, RANSModelConstants<RANS_SA_DV>>> {
127};
128template <>
129struct LsFvCombustionXD<3, FvSysEqnRANS<3, RANSModelConstants<RANS_SA_DV>>> {
131};
132
133template <MInt nDim, class SysEqn>
134struct LsFvMbXD {};
135template <>
136struct LsFvMbXD<2, FvSysEqnNS<2>> {
137 using type = LsFvMb<2, FvSysEqnNS<2>>;
138};
139template <>
140struct LsFvMbXD<3, FvSysEqnNS<3>> {
141 using type = LsFvMb<3, FvSysEqnNS<3>>;
142};
143template <>
144struct LsFvMbXD<2, FvSysEqnRANS<2, RANSModelConstants<RANS_SA_DV>>> {
146};
147template <>
148struct LsFvMbXD<3, FvSysEqnRANS<3, RANSModelConstants<RANS_SA_DV>>> {
150};
151
152template <MInt nDim, class SysEqn>
153struct CouplingLsFvXD {};
154template <>
155struct CouplingLsFvXD<2, FvSysEqnRANS<2, RANSModelConstants<RANS_SA_DV>>> {
157};
158template <>
159struct CouplingLsFvXD<3, FvSysEqnRANS<3, RANSModelConstants<RANS_SA_DV>>> {
161};
162template <>
163struct CouplingLsFvXD<2, FvSysEqnNS<2>> {
164 using type = CouplingLsFv<2, FvSysEqnNS<2>>;
165};
166template <>
167struct CouplingLsFvXD<3, FvSysEqnNS<3>> {
168 using type = CouplingLsFv<3, FvSysEqnNS<3>>;
169};
170} // namespace
171
172//--------------------------------------------------------------------------
173
186 TRACE();
187
201 g_multiSolverGrid = false;
202 g_multiSolverGrid = Context::getBasicProperty<MBool>("multiSolverGrid", AT_, &g_multiSolverGrid);
203
216 const MBool flowSolverDefault = false;
217 const auto flowSolver = Context::getBasicProperty<MBool>("flowSolver", AT_, &flowSolverDefault);
218
219 globalTimeStep = 1;
220
232 m_dualTimeStepping = false;
233 m_dualTimeStepping = Context::getBasicProperty<MBool>("dualTimeStepping", AT_, &m_dualTimeStepping);
234
247 const MBool gridGenDefault = false;
248 const auto gridGeneration = Context::getBasicProperty<MBool>("gridGenerator", AT_, &gridGenDefault);
249
250 // Check that either grid generation or the flow solver is activated
251 if(gridGeneration && flowSolver) {
252 TERMM(1, "Error: grid generation and flow solver activated.");
253 }
254 if(!gridGeneration && !flowSolver) {
255 TERMM(1, "Error: grid generation and flow solver both deactivated.");
256 }
257
271 g_dynamicLoadBalancing = Context::getBasicProperty<MBool>("dynamicLoadBalancing", AT_, &g_dynamicLoadBalancing);
272
273 g_splitMpiComm = false;
286 g_splitMpiComm = Context::getBasicProperty<MBool>("splitMpiComm", AT_, &g_splitMpiComm);
287 if(g_splitMpiComm) {
288 m_log << "Split MPI communication activated." << std::endl;
289 }
290
303 m_writeSolverTimings = false;
304 m_writeSolverTimings = Context::getBasicProperty<MBool>("writeSolverTimings", AT_, &m_writeSolverTimings);
305
317 Context::getBasicProperty<MInt>("solverTimingsWriteInterval", AT_, &m_solverTimingsWriteInterval);
318
328 Context::getBasicProperty<MInt>("solverTimingsSampleInterval", AT_, &m_solverTimingsSampleInterval);
330 TERMM(1, "solverTimingsSampleInterval <= 0");
331 }
332
343 m_writeAllSolverTimings = Context::getBasicProperty<MBool>("writeAllSolverTimings", AT_, &m_writeAllSolverTimings);
344
345 m_log << "Output of solver timings enabled: sampleInterval = " << m_solverTimingsSampleInterval
346 << ", writeInterval = " << m_solverTimingsWriteInterval << ", allTimings = " << m_writeAllSolverTimings
347 << endl;
348 }
349
350#ifdef DISABLE_OUTPUT
351 const MString message = "NOTE: skipping solution and restart IO for performance testing!";
352 m_log << message << std::endl;
353 cerr0 << message << std::endl;
354#endif
355
356
357 // Get number of spatial dimensions
358 const MInt nDim = read_nDim();
359
360 m_noSolvers = 1;
372 m_noSolvers = Context::getBasicProperty<MInt>("noSolvers", AT_, &m_noSolvers);
373
374 m_initialAdaptation = true;
386 m_initialAdaptation = Context::getBasicProperty<MBool>("initialAdaptation", AT_, &m_initialAdaptation);
387
388 DEBUG("Application::() noSolvers " << m_noSolvers, MAIA_DEBUG_LEVEL1);
389 if(globalDomainId() == 0) {
390 cerr << "m_noSolvers: " << m_noSolvers << endl;
391 }
392
393 if(gridGeneration) {
394 if(nDim == 2) {
395 GridgenPar<2>(MPI_COMM_WORLD, m_noSolvers);
396 } else {
397 GridgenPar<3>(MPI_COMM_WORLD, m_noSolvers);
398 }
399 return;
400 }
401
402 // Running with true multi-solver support but just one solver does not make sense (for now)
403 if(g_multiSolverGrid && m_noSolvers == 1) {
404 mTerm(1, AT_, "Enabling multi-solver without having more than one solver does not make sense");
405 }
406
407 MBool addSolverToGrid = false;
408 addSolverToGrid = Context::getBasicProperty<MBool>("addSolverToGrid", AT_, &addSolverToGrid);
409 // multiSolverGrid needs to be enabled for 2 or more solvers (except for the case when the second solver (post-data)
410 // is added during startup of the simulation)
411 if(m_noSolvers > 1 && !g_multiSolverGrid && !(m_noSolvers == 2 && addSolverToGrid)) {
412 TERMM(1, "Number of solvers > 1, but multiSolverGrid not enabled!");
413 }
414
415 g_timeSteps = Context::getBasicProperty<MInt>("timeSteps", AT_);
416 DEBUG("Application::() g_timeSteps " << g_timeSteps, MAIA_DEBUG_LEVEL1);
417
430 m_restartBackupInterval = Context::getBasicProperty<MInt>("restartBackupInterval", AT_, &m_restartBackupInterval);
431
443 m_maxIterations = 1;
444 m_maxIterations = Context::getBasicProperty<MInt>("maxIterations", AT_, &m_maxIterations);
445
446 m_solvers.resize(m_noSolvers);
447
459 m_noCouplers = 0;
460 if(m_noSolvers > 1) {
461 m_noCouplers = Context::getBasicProperty<MInt>("noCouplers", AT_, &m_noCouplers);
462 }
463 m_couplers.resize(m_noCouplers);
464
465 // Post-Processing
466 m_postProcessing = false;
468
469#ifndef DISABLE_OUTPUT
470 m_postProcessing = Context::getBasicProperty<MBool>("postProcessing", AT_, &m_postProcessing);
471 m_noPostProcessing = Context::getBasicProperty<MInt>("noPostProcessing", AT_, &m_noPostProcessing);
473 TERMM(1, "postProcessing is true, but the number of postprocessing solvers is 0!");
474 }
475#endif
476
490 Context::getBasicProperty<MBool>("displayMemoryStatistics", AT_, &m_displayMemoryStatistics);
491
506 m_ppAfterTS = false;
507 m_ppAfterTS = Context::getBasicProperty<MBool>("postProcessingAfterTS", AT_, &m_ppAfterTS);
508}
509
510
512 for(auto& coupler : m_couplers) {
513 coupler.reset();
514 }
515 m_couplers.clear();
516
517 for(auto& solver : m_solvers) {
518 solver.reset();
519 }
520 m_solvers.clear();
521}
522
525 TRACE();
526
527 // Return if not enabled
529 return;
530 }
531
532 const MInt noSolversAndCouplers = m_noSolvers + m_noCouplers;
533 const MBool allTimings = m_writeAllSolverTimings;
534 // Determine total number of timers and domain decomposition information of each solver/coupler
536
537 for(MInt i = 0; i < noSolversAndCouplers; i++) {
538 const MInt noTimers = (i < m_noSolvers) ? m_solvers[i]->noSolverTimers(allTimings)
539 : m_couplers[i - m_noSolvers]->noCouplingTimers(allTimings);
540 m_noGlobalSolverTimers += noTimers;
541 }
542
543 MInt maxNoGlobalSolverTimers = -1;
544 MPI_Allreduce(&m_noGlobalSolverTimers, &maxNoGlobalSolverTimers, 1, maia::type_traits<MInt>::mpiType(), MPI_MAX,
545 MPI_COMM_WORLD, AT_, "m_noGlobalSolverTimers", "maxNoGlobalSolverTimers");
546 if(maxNoGlobalSolverTimers != m_noGlobalSolverTimers) {
547 TERMM(1, "Error: number of global solver timings does not match on all domains.");
548 }
549
550 m_solverTimings.clear();
552
555
558
559 // Reserve memory for timings (should be enough to avoid reallocation during solver run)
560 for(MInt timerId = 0; timerId < m_noGlobalSolverTimers; timerId++) {
561 m_solverTimings[timerId].clear();
562 m_solverTimings[timerId].reserve(m_maxNoSolverTimings);
563
564 m_solverTimingsPrevTime[timerId] = 0.0;
565 }
566
567 for(MInt i = 0; i < noSolversAndCouplers; i++) {
568 const MInt noTimers = (i < m_noSolvers) ? m_solvers[i]->noSolverTimers(allTimings)
569 : m_couplers[i - m_noSolvers]->noCouplingTimers(allTimings);
570 // Get solver timer names
571 std::vector<std::pair<MString, MFloat>> timings{};
572 (i < m_noSolvers) ? m_solvers[i]->getSolverTimings(timings, allTimings)
573 : m_couplers[i - m_noSolvers]->getCouplingTimings(timings, allTimings);
574 ASSERT((MInt)timings.size() == noTimers, "number of timings mismatch #" + std::to_string(i) + ": "
575 + std::to_string(timings.size()) + " != " + std::to_string(noTimers));
576
577 for(MInt j = 0; j < noTimers; j++) {
578 m_solverTimingsNames.push_back(timings[j].first);
579 }
580 }
581
582 m_log << "Initialized collection of solver timings: " << m_noGlobalSolverTimers << std::endl;
583}
584
585
592template <MInt nDim>
593void Application::run() {
594 TRACE();
595 cerr0 << endl << "=== MAIA RUN LOOP ===" << endl << endl;
596 const MPI_Comm comm = MPI_COMM_WORLD;
597 const MFloat runTimeStart = wallTime();
598
599 auto logDuration = [&](const MFloat timeStart, const MString comment) {
600 logDuration_(timeStart, "RUN", comment, comm, globalDomainId(), globalNoDomains());
601 };
602
603 // Create some timers
604 NEW_TIMER_GROUP(tg_totalMainLoop, "total main loop");
605 NEW_TIMER(t_totalMainLoop, "total main loop", tg_totalMainLoop);
606 NEW_SUB_TIMER(t_adaptation, "adaptation", t_totalMainLoop);
607 NEW_SUB_TIMER(t_preTimeStep, "preTimeStep", t_totalMainLoop);
608 NEW_SUB_TIMER(t_preCouple, "preCouple", t_totalMainLoop);
609 NEW_SUB_TIMER(t_timeStep, "timeStep", t_totalMainLoop);
610 NEW_SUB_TIMER(t_postTimeStep, "postTimeStep", t_totalMainLoop);
611 NEW_SUB_TIMER(t_postCouple, "postCouple", t_totalMainLoop);
612 NEW_SUB_TIMER(t_implicitTimeStep, "Implicit time-step", t_totalMainLoop);
613
614#ifndef DISABLE_OUTPUT
615 NEW_SUB_TIMER(t_solutionOutput, "solutionOutput", t_totalMainLoop);
616#endif
617
618 NEW_SUB_TIMER(t_balance, "balance", t_totalMainLoop);
619
620 RECORD_TIMER_START(t_totalMainLoop);
621
622 for(MInt i = 0; i < m_noSolvers; i++) {
623 // Create separate output directory for this solver if it does not exist yet
624 if(globalDomainId() == 0) {
625 const MString outputDir = Context::getSolverProperty<MString>("outputDir", i, AT_);
626 createDir(outputDir);
627 }
628 }
629
630 const MFloat geometryTimeStart = wallTime();
631 // Create Geometries (for solvers using cartesian grid)
632 vector<typename GeometryXD<nDim>::type*> geometries;
633 for(MInt solverId = 0; solverId < m_noSolvers; solverId++) {
634 const MString solverType = Context::getSolverProperty<MString>("solvertype", solverId, AT_);
635 if(gridType(solverType) == MAIA_GRID_CARTESIAN) {
636 geometries.push_back(new typename GeometryXD<nDim>::type(solverId, comm));
637 } else {
638 geometries.push_back(nullptr);
639 }
640 }
641 logDuration(geometryTimeStart, "Create geometries");
642
643 // Enable auto-save feature:
644 MInt noMinutesEndAutoSave = 5;
645 noMinutesEndAutoSave = Context::getBasicProperty<MInt>("noMinutesEndAutoSave", AT_, &noMinutesEndAutoSave);
646
647 MInt endAutoSaveTime = -1;
648 const char* envJobEndTime = getenv("MAIA_JOB_END_TIME");
649 if(envJobEndTime) {
650 const MString jobEndTime(envJobEndTime);
651 MBool onlyDigits = true;
652 for(auto&& character : jobEndTime) {
653 if(!isdigit(character)) {
654 m_log << "Warning: the environment variable MAIA_JOB_END_TIME includes "
655 << "non-digit characters.\n"
656 << "Saving a restart file before the compute job ends is NOT active." << endl;
657 onlyDigits = false;
658 break;
659 }
660 }
661 if(onlyDigits) {
662 endAutoSaveTime = stoi(jobEndTime);
663 endAutoSaveTime -= noMinutesEndAutoSave * 60;
664 time_t time_point = endAutoSaveTime;
665 m_log << "Activated automatic restart file writing at " << ctime(&time_point)
666 << " (in Unix time: " << endAutoSaveTime << ")." << endl;
667 }
668 }
669
670 // Seed RNG
682 const MBool seedRNGWithTime = false;
683 if(Context::getBasicProperty<MBool>("seedRNGWithTime", AT_, &seedRNGWithTime)) {
684 if(Context::propertyExists("RNGSeed")) mTerm(1, "Property RNGSeed and seedRNGWithTime are exclusive!");
685 srand(time(nullptr));
686 } else {
697 MInt seed = 0;
698 seed = Context::getBasicProperty<MInt>("RNGSeed", AT_, &seed);
699 if(seed < 0) mTerm(1, "RNGSeed has to be a positive integer.");
700 srand(static_cast<MUint>(seed));
701 }
702
703 // Create Grid
704 cerr0 << "=== Create grid..." << endl;
705 const MFloat gridTimeStart = wallTime();
706
707 CartesianGrid<nDim>* grid = nullptr;
708#ifndef MAIA_DISABLE_STRUCTURED
709 StructuredGrid<nDim>* gridStructured = nullptr;
710#endif
711 MBool structuredGridExist = false;
712 MBool cartGridExist = false;
713
714 for(MInt i = 0; i < m_noSolvers; i++) {
715 const MString solverType = Context::getSolverProperty<MString>("solvertype", i, AT_);
716 const MInt solverGridType = gridType(solverType);
717
718 if(solverGridType == MAIA_GRID_STRUCTURED) {
719 if(!structuredGridExist) {
720 // Create Grid
721 cerr0 << "=== Create structured grid..." << endl;
722#ifndef MAIA_DISABLE_STRUCTURED
723 gridStructured = new StructuredGrid<nDim>(i, comm);
724#endif
725 cerr0 << "=== done." << endl;
726 structuredGridExist = true;
727 }
728 } else if(solverGridType == MAIA_GRID_CARTESIAN) {
729 if(!cartGridExist) {
730 // Create Grid
731 cerr0 << "=== Create Cartesian grid..." << endl;
732 // TODO: Determination of maxNoCells is already done at environment level
733 MInt maxNoCells = Context::getBasicProperty<MInt>("maxNoCells", AT_);
734 if(Context::propertyExists("noDomains")) {
735 const MInt testNoDomains = Context::getBasicProperty<MInt>("noDomains", AT_, 0);
736 if(globalNoDomains() < testNoDomains) {
737 // Here, the number of maxNoCells is scaled. This is useful if a test
738 // case is specified to run with a certain number of ranks
739 // ('noDomains' property in run.toml) but needs to be run on a lower
740 // number of mpiranks, p.e. by running maia on an accelerator.
741 maxNoCells *= testNoDomains / (MFloat)globalNoDomains();
742 cerr0 << "noDomain > number of used mpi ranks! Therefore, increasing maxNoCells: " << maxNoCells
743 << std::endl;
744 }
745 }
746 grid = new CartesianGrid<nDim>(maxNoCells, (geometries[0])->boundingBox(), comm);
747 cerr0 << "=== done." << endl;
748 cartGridExist = true;
749 }
750 } else if(solverGridType == MAIA_GRID_NONE) {
751 continue;
752 } else {
753 TERMM(1, "Invalid grid type: " + std::to_string(solverGridType));
754 }
755 }
756 logDuration(gridTimeStart, "Create grid");
757
758 // Read in the propertiesGroups, which were before set in initMehtods()
759 MBool* propertiesGroups = readPropertiesGroups();
760 std::vector<MBool> isActive(m_noSolvers, false);
761
762 // Create Solvers
763 const MFloat createSolversTimeStart = wallTime();
764 cerr0 << "=== Create solvers..." << endl;
765
766 for(MInt i = 0; i < m_noSolvers; i++) {
767 const MFloat createSolverTimeStart = wallTime();
768 MBool active = false;
769 const MString solverType = Context::getSolverProperty<MString>("solvertype", i, AT_);
770 const MInt solverGridType = gridType(solverType);
771
772 if(solverGridType == MAIA_GRID_STRUCTURED) {
773 ASSERT(structuredGridExist, "");
774 cerr0 << "=== Create structured solver..." << endl;
775#ifndef MAIA_DISABLE_STRUCTURED
776 createSolver<nDim>(gridStructured, i, propertiesGroups, comm);
777#endif
778 cerr0 << "=== done." << endl;
779 } else if(solverGridType == MAIA_GRID_CARTESIAN) {
780 ASSERT(cartGridExist, "");
781 cerr0 << "=== Create " << solverType << "..." << endl;
782 createSolver<nDim>(grid, i, geometries[i], propertiesGroups, active);
783 cerr0 << "=== done." << endl;
784 } else if(solverGridType == MAIA_GRID_NONE) {
785 cerr0 << "=== Create gridless solver " << solverType << "..." << endl;
786 createSolver<nDim>(i, comm);
787 cerr0 << "=== done." << endl;
788 } else {
789 TERMM(1, "Invalid grid type: " + std::to_string(solverGridType));
790 }
791
792 isActive[i] = active;
793 logDuration(createSolverTimeStart, "Create solver #" + std::to_string(i));
794 }
795 logDuration(createSolversTimeStart, "Create solvers");
796
797 // No longer needed at that point
798 delete[] propertiesGroups;
799
800 // Create solver couplers
801 const MFloat couplersTimeStart = wallTime();
802 cerr0 << "=== Create couplers..." << endl;
803 for(MInt i = 0; i < m_noCouplers; i++) {
804 createCoupler<nDim>(i);
805 }
806 cerr0 << "=== done." << endl;
807 logDuration(couplersTimeStart, "Create couplers");
808
809 globalTimeStep = 0;
810 MInt restartTimeStep = -1;
811
812 MBool restartFile = false;
813 restartFile = Context::getBasicProperty<MBool>("restartFile", AT_, &restartFile);
814
815 // Set the correct global time step (at a restart)
816 globalTimeStep = getInitialTimeStep(restartFile, comm);
817 restartTimeStep = globalTimeStep;
819
820 // Create grid controller
821 const MFloat controllerTimeStart = wallTime();
822 cerr0 << "=== Create grid controller..." << endl;
823 typename ::maia::grid::Controller<nDim> controller(grid, &m_solvers, &m_couplers);
824 cerr0 << "=== done." << endl;
825 logDuration(controllerTimeStart, "Create grid controller");
826
827 // Create PostProcessing controller
828 PostProcessingController<nDim>* ppController = nullptr;
829 std::vector<PostProcessingInterface*> pp;
830
831 // Init solvers - solverId in propertiesFile determines solver order
832 const MFloat initSolversTimeStart = wallTime();
833 cerr0 << "=== Init solvers..." << endl;
834 for(MInt i = 0; i < m_noSolvers; i++) {
835 const MFloat initSolverTimeStart = wallTime();
836 m_solvers[i]->initSolver();
837 logDuration(initSolverTimeStart, "Init solver #" + std::to_string(i));
838
840 writeMemoryStatistics(comm, globalNoDomains(), globalDomainId(), AT_, "solver init #" + std::to_string(i));
841 }
842 }
843 logDuration(initSolversTimeStart, "Init solvers");
844 cerr0 << "=== done." << endl;
845
846
847 // Init couplers - couplerId in propertiesFile determines coupler order
848 const MFloat initCouplersTimeStart = wallTime();
849 cerr0 << "=== Init couplers..." << endl;
850 for(auto&& coupler : m_couplers) {
851 coupler->init();
852 }
853 logDuration(initCouplersTimeStart, "Init couplers");
855 writeMemoryStatistics(comm, globalNoDomains(), globalDomainId(), AT_, "coupler init");
856 }
857
858 // Switch to fully disable/ignore all DLB timers
859 MBool ignoreDlbTimers = false;
860 ignoreDlbTimers = Context::getBasicProperty<MBool>("ignoreDlbTimers", AT_, &ignoreDlbTimers);
861 // Prevent disabled DLB timers to be used for any performance output since its useless in this case
862 if(ignoreDlbTimers) {
863 const MBool performanceOutput = Context::getBasicProperty<MBool>("performanceOutput", AT_);
864 TERMM_IF_COND(performanceOutput,
865 "ERROR: ignoreDlbTimers=true should only be used together with performanceOutput=false");
866 }
867
868 // Create DLB timers for solvers and couplers
870 m_log << "Created " << m_noSolvers + m_noCouplers << " DLB timers (ignore = " << ignoreDlbTimers << ")" << std::endl;
871
872 // Assign each solver/coupler its DLB timer id
873 for(MInt i = 0; i < m_noSolvers; i++) {
874 m_solvers[i]->setDlbTimer(i);
875 }
876 for(MInt i = 0; i < m_noCouplers; i++) {
877 m_couplers[i]->setDlbTimer(m_noSolvers + i);
878 }
879
880 cerr0 << "=== done." << endl;
881
882 MBool forceInitialAdaptation = false;
883 for(MInt solverId = 0; solverId < m_noSolvers; solverId++) {
884 if(m_solvers[solverId]->forceAdaptation()) {
885 forceInitialAdaptation = true;
886 cerr0 << "=== Forcing Initial adaptation: " << endl;
887 break;
888 }
889 }
890
891 // Initial adaptation - can be turned off by setting initialAdaptation = false
892 if(!restartFile || forceInitialAdaptation) {
893 cerr0 << "=== Initial adaptation..." << endl;
894 const MInt gtbak = globalTimeStep;
895 globalTimeStep = -1;
896 RECORD_TIMER_START(t_adaptation);
897 controller.adaptation(m_initialAdaptation);
898 RECORD_TIMER_STOP(t_adaptation);
899 globalTimeStep = gtbak;
900
901 MBool outputInitialAdaptation = false;
902 outputInitialAdaptation =
903 Context::getBasicProperty<MBool>("outputInitialAdaptation", AT_, &outputInitialAdaptation);
904 if(!restartFile && outputInitialAdaptation) {
905 controller.writeRestartFile(true, false);
906 }
907 cerr0 << "=== done." << endl;
908 }
909
910 // Finalize solvers
911 const MFloat finalizeInitTimeStart = wallTime();
912 cerr0 << "=== Finalize initialization of solvers and couplers..." << endl;
913
914 for(MInt i = 0; i < m_noSolvers; i++) {
915 const MFloat finalizeInitSolverTimeStart = wallTime();
916 m_solvers[i]->finalizeInitSolver();
917 if(geometries[i] != nullptr) {
918 geometries[i]->logStatistics();
919 }
920 // Some solvers need coupler information before they can be finalized!
921 // NOTE: If couplers were to know solverIds of the solvers they couple, a call of each coupler after each finalize
922 // could be prevented!
923 for(auto&& coupler : m_couplers) {
924 coupler->finalizeSubCoupleInit(i);
925 }
926 logDuration(finalizeInitSolverTimeStart, "Finalize initialization solver #" + std::to_string(i));
927 }
928 logDuration(finalizeInitTimeStart, "Finalize initialization");
929
930 // Finalize couplers
931 const MFloat finalizeCouplerInitTimeStart = wallTime();
932 for(auto&& coupler : m_couplers) {
933 coupler->finalizeCouplerInit();
934 }
935 cerr0 << "=== done." << endl;
936
937
938 logDuration(finalizeCouplerInitTimeStart, "Finalize coupler init");
939
940 if(m_postProcessing) {
941 pp.clear();
942 cerr0 << "=== Init postprocessing..." << endl;
943 for(MInt ppId = 0; ppId < (MInt)m_noPostProcessing; ppId++) {
944 pp.push_back(createPostProcessing<nDim>(ppId));
945 }
946
947 ppController = new PostProcessingController<nDim>(pp);
948
949 ppController->init();
950 ppController->preSolve();
951
952 cerr0 << "=== done." << endl;
953 }
954
955 MBool outputInitialCondition = false;
956 outputInitialCondition = Context::getBasicProperty<MBool>("outputInitialCondition", AT_, &outputInitialCondition);
957 MBool writePostprocessingPre = false;
958 writePostprocessingPre = Context::getBasicProperty<MBool>("writePostprocessingPre", AT_, &writePostprocessingPre);
959 const MBool initialBackup = globalTimeStep > 0 && globalTimeStep % m_restartBackupInterval == 0;
960 if((outputInitialCondition && (!restartFile || forceInitialAdaptation)) || writePostprocessingPre) {
961 controller.writeRestartFile(true, initialBackup);
962 }
963
964 // Update partition cell workloads if enabled and save to the grid file, cleanup, then quit.
965 if(controller.updateGridPartitionWorkloads()) {
966 cleanUp();
967 return;
968 }
969
970 // Initialize timings for dynamic load balancing
971 initTimings();
972
973 // Create execution recipe in executionrecipe.h
974 ExecutionRecipe* recipe = createRecipe();
975
976 // Memory statistics for each process
978 writeMemoryStatistics(comm, globalNoDomains(), globalDomainId(), AT_, "After initialization");
979 }
980
981 // Alive output during simulation
994 MInt aliveInterval = 0;
995 aliveInterval = Context::getBasicProperty<MInt>("aliveInterval", AT_, &aliveInterval);
996 if(aliveInterval < 0) {
997 TERMM(1, "Alive interval must be >= 0 (is: " + to_string(aliveInterval) + ").");
998 }
999 const MFloat loopTimeStart = wallTime();
1000 MFloat lastRunTime = 0.0;
1001 MInt lastGlobalTimeStep = globalTimeStep;
1002
1004 MBool finalTimeStep = (globalTimeStep) >= (g_timeSteps + restartTimeStep);
1005
1006 MBool debugOutputAfterBalance = false;
1007 debugOutputAfterBalance = Context::getBasicProperty<MBool>("debugOutputAfterBalance", AT_, &debugOutputAfterBalance);
1008
1009 // set finale timeStep if auto-save feature is enabled!
1010 if(endAutoSaveTime != -1
1011 && endAutoSaveTime
1012 <= chrono::duration_cast<chrono::seconds>(chrono::system_clock::now().time_since_epoch()).count()) {
1013 finalTimeStep = true;
1014 }
1015
1016 logDuration(runTimeStart, "Full initialization");
1017
1018 // Enable DLB timers
1020
1021 while(globalTimeStep < (g_timeSteps + restartTimeStep)) {
1023 finalTimeStep = (globalTimeStep) >= (g_timeSteps + restartTimeStep);
1024
1025 // Advance time step loop
1026 MBool advanceTimeStep = false;
1027 while(!advanceTimeStep) {
1028 // Check whether a solver adaptation is allowed during a specific iteration step
1029 if(recipe->callAdaptation()) {
1030
1031 MBool force = false;
1032 for(MInt solverId = 0; solverId < m_noSolvers; solverId++) {
1033 if(m_solvers[solverId]->forceAdaptation()) {
1034 force = true;
1035 m_log << "Solver " << solverId << " is forcing a mesh-adaptation at time-step " << globalTimeStep << endl;
1036 break;
1037 }
1038 }
1039
1041
1042 if(force || controller.isAdaptationTimeStep()) {
1044 }
1045
1046 RECORD_TIMER_START(t_adaptation);
1047 const MBool wasAdapted = controller.adaptation(force);
1048 RECORD_TIMER_STOP(t_adaptation);
1049
1050 if(wasAdapted && m_displayMemoryStatistics) {
1051 writeMemoryStatistics(comm, globalNoDomains(), globalDomainId(), AT_, "After adaptation");
1052 }
1053
1055 }
1056
1057 // Call preTimeStep() in each solver via the executionrecipe
1058 RECORD_TIMER_START(t_preTimeStep);
1059 recipe->preTimeStep();
1060 RECORD_TIMER_STOP(t_preTimeStep);
1061
1062 // Call preCouple() in each coupler via the executionrecipe
1063 RECORD_TIMER_START(t_preCouple);
1064 recipe->preCouple();
1065 RECORD_TIMER_STOP(t_preCouple);
1066
1067 // Advance the time step according to the specified recipe
1068 RECORD_TIMER_START(t_timeStep);
1069 recipe->timeStep();
1070 RECORD_TIMER_STOP(t_timeStep);
1071
1072 // Post-Processing InSolve before postTS and postCouple
1074 ppController->setStep(recipe->a_step());
1075 ppController->inSolve(finalTimeStep);
1076 }
1077
1078 // Call postTimeStep() in each solver via the executionrecipe
1079 RECORD_TIMER_START(t_postTimeStep);
1080 recipe->postTimeStep();
1081 RECORD_TIMER_STOP(t_postTimeStep);
1082
1083 // Call postCouple() in each coupler via the executionrecipe
1084 RECORD_TIMER_START(t_postCouple);
1085 recipe->postCouple();
1086 RECORD_TIMER_STOP(t_postCouple);
1087
1088 // Post-Processing InSolve after postTS and postCoupl
1090 ppController->setStep(recipe->a_step());
1091 ppController->inSolve(finalTimeStep);
1092 }
1093
1094 // Determine wich solvers are active during each iterarion step
1095 advanceTimeStep = recipe->updateCallOrder();
1096 // URL
1097 }
1098
1099 // Dual time stepping - probably not working!
1100 if(m_dualTimeStepping) {
1101 RECORD_TIMER_START(t_implicitTimeStep);
1102 for(MInt i = 0; i < m_noSolvers; i++) {
1103 m_solvers[i]->implicitTimeStep();
1104 }
1105 RECORD_TIMER_STOP(t_implicitTimeStep);
1107 }
1108
1109 // Check if each solvers solution is converged. If so, write a restartFile and exit time step loop.
1110 MBool completed = true;
1111 for(MInt i = 0; i < m_noSolvers; i++) {
1112 // Note: solverConverged() is a prototype that only exists in solver.h and always returns false
1113 // ansgar: for the DG solver, solverConverged() returns true if the final solution time
1114 // T_end is reached
1115 if(m_solvers[i]->isActive()) {
1116 // TODO labels:totest if there are inactive ranks for a solver these do not have the converged info!
1117 completed &= m_solvers[i]->solverConverged();
1118 }
1119 }
1120
1121 // TODO labels:noissue this is just to ensure that in a multisolver computation with inactive ranks the
1122 // converged info does not lead to ranks exiting the run loop while others continue!
1123 if(m_noSolvers > 1) {
1124#ifndef NDEBUG
1125 if(completed) {
1126 std::cerr << "Warning: one or multiple solvers in a multisolver computation returned a "
1127 "'completed' status, however this information might not be consistent among "
1128 "ranks if there are inactive ranks!"
1129 << std::endl;
1130 }
1131#endif
1132
1133 completed = false;
1134 }
1135
1136 finalTimeStep = finalTimeStep || completed;
1137
1138 // set finale timeStep if auto-save feature is enabled!
1139 if(endAutoSaveTime != -1
1140 && endAutoSaveTime
1141 <= chrono::duration_cast<chrono::seconds>(chrono::system_clock::now().time_since_epoch()).count()) {
1142 finalTimeStep = true;
1143
1144 time_t now =
1145 std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now().time_since_epoch()).count();
1146
1147 m_log << "Finished end auto save at " << std::ctime(&now) << " (in Unix time: " << now << ")." << endl;
1148 time_t remaining_time = endAutoSaveTime - now;
1149 m_log << "Job will end at" << std::ctime(&remaining_time) << " (in Unix time: " << remaining_time << ")." << endl;
1150 }
1151
1152#ifndef DISABLE_OUTPUT
1153 const MBool forceOutput = false;
1154 RECORD_TIMER_START(t_solutionOutput);
1155
1156 // Write the restart files via the gridController
1157 const MBool backup = (globalTimeStep % m_restartBackupInterval == 0) && (globalTimeStep > 0);
1158 controller.writeRestartFile(finalTimeStep, backup);
1159 // extRestartFile(finalTimeStep);
1160
1161 // Solver specific solution output
1162 // TODO labels:GRID save also adapted grid if there is no restart file written at the same time and update the
1163 // grid file name
1164 for(MInt i = 0; i < m_noSolvers; i++) {
1165 if(m_solvers[i]->isActive()) {
1166 m_solvers[i]->disableDlbTimers();
1167 m_solvers[i]->saveSolverSolution(forceOutput, finalTimeStep);
1168 m_solvers[i]->enableDlbTimers();
1169 }
1170 }
1171
1172 // Post-Processing InSolve write solution files
1173 if(m_postProcessing) {
1174 ppController->ppSolution();
1175 }
1176
1177 RECORD_TIMER_STOP(t_solutionOutput);
1178#endif
1179
1180 // Save timings for dynamic load balancing for this time step
1184
1185 // If all solvers are convered the time step loop is terminated
1186 // if (completed) { break; } // Note: moved to end of loop to allow DLB imbalance evaluation
1187
1188 // Prepare balance and next time step
1189 // E.g. fvMbSolver needs to update his old variables with the new variables after it wrote its restartFile but
1190 // before load balancing can be performed
1191 for(MInt i = 0; i < m_noSolvers; i++) {
1192 m_solvers[i]->prepareNextTimeStep();
1193
1194 // log statistics to check the balance/distribution
1195 // if(i == 0 && globalTimeStep % 50 == 0) {
1196 // m_solvers[i]->disableDlbTimers();
1197 // controller.logTimerStatistics("regular at timeStep");
1198 // m_solvers[i]->enableDlbTimers();
1199 //}
1200 }
1201
1202 // Load balancing
1204 RECORD_TIMER_START(t_balance);
1205 if(controller.isDlbTimeStep()) {
1207 }
1208
1209 const MBool wasBalanced = controller.balance(false, finalTimeStep, false);
1210 RECORD_TIMER_STOP(t_balance);
1211
1212 if(wasBalanced && m_displayMemoryStatistics) {
1213 writeMemoryStatistics(comm, globalNoDomains(), globalDomainId(), AT_, "After load balancing");
1214 }
1215
1217
1218 // Alive output during simulation
1219 if(aliveInterval > 0 && globalTimeStep % aliveInterval == 0 && globalDomainId() == 0) {
1220 // Calculate total run time for printing
1221 const MFloat runTimeTotal = wallTime() - loopTimeStart;
1222 const MFloat runTimePerStep =
1223 (runTimeTotal - lastRunTime) / static_cast<MFloat>(globalTimeStep - lastGlobalTimeStep);
1224 lastRunTime = runTimeTotal;
1225 lastGlobalTimeStep = globalTimeStep;
1226
1227 // Print out processing information to user
1228 printf("#t/s: %8d | Run time: %.4e s | Time/step: %.4e s\n", globalTimeStep, runTimeTotal, runTimePerStep);
1229 }
1230
1231 if(debugOutputAfterBalance && wasBalanced) {
1232 if(globalDomainId() == 0) {
1233 printf("------------Write debug restart after balance------------");
1234 }
1235 controller.writeRestartFile(true, false);
1236 }
1237
1238 // If all solvers are converged the time step loop is terminated
1239 if(completed || finalTimeStep) {
1240 break;
1241 }
1242 } // end globalTimeStep loop
1243
1244 // Disable DLB timers for remaining steps
1246
1247 writeMemoryStatistics(comm, globalNoDomains(), globalDomainId(), AT_, "After run loop");
1248
1249 // If grid was balanced save final partition file for restarting
1250 controller.savePartitionFile();
1251
1252 // Post-Processing PostSolve
1253 // @Jannik: this must happen before the cleanUp, where data-structure might be destroyed
1254 // and destructors called!
1255 if(m_postProcessing) {
1256 ppController->postSolve();
1257 }
1258
1259 cleanUp();
1260
1261 RECORD_TIMER_STOP(t_totalMainLoop);
1262}
1263
1264
1266MInt Application::getInitialTimeStep(const MBool restartFile, const MPI_Comm comm) {
1267 TRACE();
1268 if(!restartFile) {
1269 return 0;
1270 } else {
1271 MBool useNonSpecifiedRestartFile = false;
1272 useNonSpecifiedRestartFile =
1273 Context::getBasicProperty<MBool>("useNonSpecifiedRestartFile", AT_, &useNonSpecifiedRestartFile);
1274
1275 if(!useNonSpecifiedRestartFile) {
1276 // Use given restart time step from properties
1277 return Context::getBasicProperty<MInt>("restartTimeStep", AT_);
1278 } else {
1279 // Restart time step not specified in properties, use the first suitable solver on rank 0 to
1280 // load time step from restart file and broadcast result
1281 MInt timeStep = -1;
1282 // TODO labels:totest,noissue this will not work if rank 0 does not have a solver with restart time step
1283 // information!
1284 if(globalDomainId() == 0) {
1285 for(MInt solver = 0; solver < m_noSolvers; solver++) {
1286 if(m_solvers[solver]->hasRestartTimeStep()) {
1287 timeStep = m_solvers[solver]->determineRestartTimeStep();
1288 break;
1289 }
1290 }
1291 }
1292 MPI_Bcast(&timeStep, 1, maia::type_traits<MInt>::mpiType(), 0, comm, AT_, "timeStep");
1293 m_log << "Determined global time step from restart file: " << timeStep << std::endl;
1294 return timeStep;
1295 }
1296 }
1297}
1298
1299
1305 TRACE();
1306
1307 MBool tmpFalse = false;
1308
1309 auto* propertiesGroups = new MBool[PROPERTIESGROUPS_COUNT];
1310
1311 fill(propertiesGroups, propertiesGroups + PROPERTIESGROUPS_COUNT, tmpFalse);
1312
1313 propertiesGroups[LEVELSETMB] = Context::getBasicProperty<MBool>("levelSetMb", AT_, &tmpFalse);
1314 propertiesGroups[LEVELSET] = Context::getBasicProperty<MBool>("levelSet", AT_, &tmpFalse);
1315 propertiesGroups[LB] = Context::getBasicProperty<MBool>("lb", AT_, &tmpFalse);
1316 propertiesGroups[LS_SOLVER] = Context::getBasicProperty<MBool>("lsSolver", AT_, &tmpFalse);
1317 propertiesGroups[COMBUSTION] = Context::getBasicProperty<MBool>("combustion", AT_, &tmpFalse);
1318 propertiesGroups[DG] = Context::getBasicProperty<MBool>("DG", AT_, &tmpFalse);
1319 propertiesGroups[LS_RANS] = Context::getBasicProperty<MBool>("levelSetRans", AT_, &tmpFalse);
1320
1321 MString couplerTypeDefault = "";
1322 MString couplerType = Context::getBasicProperty<MString>("couplerType_0", AT_, &couplerTypeDefault);
1323 propertiesGroups[LEVELSET_LB] = couplerType == "COUPLER_LS_LB";
1324
1325 if(globalDomainId() == 0) {
1326 cerr << "FV-MB is " << ((propertiesGroups[LEVELSETMB]) ? "on" : "off") << endl;
1327 cerr << "FV-LS is " << ((propertiesGroups[LEVELSET]) ? "on" : "off") << endl;
1328 cerr << "LB is " << ((propertiesGroups[LB]) ? "on" : "off") << endl;
1329 cerr << "LB LS is " << ((propertiesGroups[LEVELSET_LB]) ? "on" : "off") << endl;
1330 cerr << "LS SOLVER is " << ((propertiesGroups[LS_SOLVER]) ? "on" : "off") << endl;
1331 cerr << "COMBUSTION is " << ((propertiesGroups[COMBUSTION]) ? "on" : "off") << endl;
1332 cerr << "DG is " << ((propertiesGroups[DG]) ? "on" : "off") << endl;
1333 cerr << "LS-RANS is " << ((propertiesGroups[LS_RANS]) ? "on" : "off") << endl;
1334 }
1335
1336 return propertiesGroups;
1337}
1338
1339
1342 switch(string2enum(solverType)) {
1343 case MAIA_STRUCTURED: {
1344 return MAIA_GRID_STRUCTURED;
1345 }
1346 case MAIA_ACOUSTIC_ANALOGY: {
1347 return MAIA_GRID_NONE; // No grid required for acoustic extrapolation (e.g. FWH)
1348 }
1349 default: { // Default Cartesian grid
1350 return MAIA_GRID_CARTESIAN;
1351 }
1352 }
1353}
1354
1355
1360template <MInt nDim>
1362 MBool* propertiesGroups, MBool& isActive) {
1363 TRACE();
1364
1365
1366 // Determine solver type from property file
1367 const MString solverType = Context::getSolverProperty<MString>("solvertype", solverId, AT_);
1368
1369 grid::Proxy<nDim>* gridProxy = nullptr;
1370 gridProxy = new grid::Proxy<nDim>(solverId, *grid, *geometry);
1371 isActive = gridProxy->isActive();
1372
1373 // Now create the specified solver
1374 switch(string2enum(solverType)) {
1375 case MAIA_LEVELSET_SOLVER: {
1376 m_solvers[solverId] = LsCartesianSolverFactory<nDim>::create(solverId, propertiesGroups, *gridProxy, *geometry,
1377 gridProxy->mpiComm());
1378 break;
1379 }
1380 case MAIA_FINITE_VOLUME: {
1381 MInt noSpecies = 0;
1382 noSpecies = Context::getSolverProperty<MInt>("noSpecies", solverId, AT_, &noSpecies);
1383 MInt fvSystemEquations = string2enum("FV_SYSEQN_NS");
1384 if(Context::propertyExists("fvSystemEquations", solverId)) {
1385 fvSystemEquations = string2enum(Context::getSolverProperty<MString>("fvSystemEquations", solverId, AT_));
1386 }
1387 MString ransMethod = "";
1388 if(Context::propertyExists("ransMethod", solverId)) {
1389 ransMethod = Context::getSolverProperty<MString>("ransMethod", solverId, AT_);
1390 }
1391 // cerr << ransMethod << endl;
1392 switch(fvSystemEquations) {
1393 case FV_SYSEQN_RANS: {
1394 switch(string2enum(ransMethod)) {
1395 case RANS_SA:
1396 case RANS_SA_DV: {
1397 m_solvers[solverId] =
1398 make_unique<FvCartesianSolverXD<nDim, FvSysEqnRANS<nDim, RANSModelConstants<RANS_SA_DV>>>>(
1399 solverId, noSpecies, propertiesGroups, *gridProxy, *geometry, gridProxy->mpiComm());
1400 break;
1401 }
1402 case RANS_FS: {
1403 m_solvers[solverId] =
1404 make_unique<FvCartesianSolverXD<nDim, FvSysEqnRANS<nDim, RANSModelConstants<RANS_FS>>>>(
1405 solverId, noSpecies, propertiesGroups, *gridProxy, *geometry, gridProxy->mpiComm());
1406 break;
1407 }
1408 case RANS_KOMEGA: {
1409 m_solvers[solverId] =
1410 make_unique<FvCartesianSolverXD<nDim, FvSysEqnRANS<nDim, RANSModelConstants<RANS_KOMEGA>>>>(
1411 solverId, noSpecies, propertiesGroups, *gridProxy, *geometry, gridProxy->mpiComm());
1412 break;
1413 }
1414 default: {
1415 TERMM(1, "Unknown RANS model for solver " + to_string(solverId));
1416 }
1417 }
1418 break;
1419 }
1420 case FV_SYSEQN_EEGAS: {
1421 IF_CONSTEXPR(nDim == 2)
1422 mTerm(1, AT_, "FVSysEqnEEGas is not tested for 2D at all and probably does not make much sense!");
1423 else m_solvers[solverId] = make_unique<FvCartesianSolverXD<nDim, FvSysEqnEEGas<nDim>>>(
1424 solverId, noSpecies, propertiesGroups, *gridProxy, *geometry, gridProxy->mpiComm());
1425 break;
1426 }
1427 case FV_SYSEQN_NS: {
1428 m_solvers[solverId] = make_unique<FvCartesianSolverXD<nDim, FvSysEqnNS<nDim>>>(
1429 solverId, noSpecies, propertiesGroups, *gridProxy, *geometry, gridProxy->mpiComm());
1430 break;
1431 }
1432 case FV_SYSEQN_DETCHEM: {
1433 m_solvers[solverId] = make_unique<FvCartesianSolverXD<nDim, FvSysEqnDetChem<nDim>>>(
1434 solverId, noSpecies, propertiesGroups, *gridProxy, *geometry, gridProxy->mpiComm());
1435 break;
1436 }
1437 default:
1438 TERMM(1, "Unsupported system of equations.");
1439 }
1440 break;
1441 }
1442 case MAIA_FV_APE: {
1443 // TODO labels:FV switch to FV-solver with fvSystemEquations=APE?
1444 m_solvers[solverId] = make_unique<typename FvApeSolverXD<nDim>::type>(solverId, 0, propertiesGroups, *gridProxy,
1445 *geometry, gridProxy->mpiComm());
1446 break;
1447 }
1448 case MAIA_FV_MB: {
1449 MInt noSpecies = 0;
1450 noSpecies = Context::getSolverProperty<MInt>("noSpecies", solverId, AT_, &noSpecies);
1451 MInt fvSystemEquations = string2enum("FV_SYSEQN_NS");
1452 if(Context::propertyExists("fvSystemEquations", solverId)) {
1453 fvSystemEquations = string2enum(Context::getSolverProperty<MString>("fvSystemEquations", solverId, AT_));
1454 }
1455 switch(fvSystemEquations) {
1456 case FV_SYSEQN_RANS: {
1457 m_solvers[solverId] =
1458 make_unique<FvMbCartesianSolverXD<nDim, FvSysEqnRANS<nDim, RANSModelConstants<RANS_SA_DV>>>>(
1459 solverId, noSpecies, propertiesGroups, *gridProxy, *geometry, gridProxy->mpiComm());
1460 break;
1461 }
1462 case FV_SYSEQN_NS: {
1463 m_solvers[solverId] = make_unique<FvMbCartesianSolverXD<nDim, FvSysEqnNS<nDim>>>(
1464 solverId, noSpecies, propertiesGroups, *gridProxy, *geometry, gridProxy->mpiComm());
1465 break;
1466 }
1467 default:
1468 TERMM(1, "Unsupported system of equations.");
1469 }
1470 break;
1471 }
1473 const MInt dgSystemEquations =
1474 string2enum(Context::getSolverProperty<MString>("dgSystemEquations", solverId, AT_));
1475 switch(dgSystemEquations) {
1477 m_solvers[solverId] = make_unique<DgCartesianSolver<nDim, DgSysEqnAcousticPerturb<nDim>>>(
1478 solverId, *gridProxy, *geometry, gridProxy->mpiComm());
1479 break;
1480 }
1482 m_solvers[solverId] = make_unique<DgCartesianSolver<nDim, DgSysEqnLinearScalarAdv<nDim>>>(
1483 solverId, *gridProxy, *geometry, gridProxy->mpiComm());
1484 break;
1485 }
1486 default:
1487 TERMM(1, "Unsupported system of equations.");
1488 }
1489 break;
1490 }
1492 m_solvers[solverId] =
1493 maia::lb::LbSolverFactory<nDim>::create(solverId, *gridProxy, *geometry, gridProxy->mpiComm());
1494 break;
1495 }
1496 case MAIA_FINITE_CELL: {
1497 m_solvers[solverId] = make_unique<FcSolver<nDim>>(solverId, *gridProxy, *geometry, gridProxy->mpiComm());
1498 break;
1499 }
1500 case MAIA_PARTICLE: {
1501 IF_CONSTEXPR(nDim == 3) {
1502 m_solvers[solverId] = make_unique<LPT<nDim>>(solverId, *gridProxy, *geometry, gridProxy->mpiComm());
1503 }
1504 else {
1505 TERMM(-1, "LPT not currently supported in 2D");
1506 }
1507 break;
1508 }
1509 case MAIA_RIGID_BODIES: {
1510 m_solvers[solverId] = make_unique<RigidBodies<nDim>>(solverId, *gridProxy, *geometry, gridProxy->mpiComm());
1511 break;
1512 }
1513 case MAIA_POST_DATA: {
1514 m_solvers[solverId] = make_unique<PostData<nDim>>(solverId, *gridProxy, *geometry, gridProxy->mpiComm());
1515 if(m_postDataSolverId != -1) TERMM(1, "Currently not more than 1 PostData possible!");
1516 m_postDataSolverId = solverId;
1517 break;
1518 }
1519 default: {
1520 TERMM(1, "Unknown solver type '" + solverType + "', exiting ... ");
1521 }
1522 }
1523
1524 m_log << "Created solver #" << std::to_string(solverId) << ": " << solverType
1525 << m_solvers[solverId]->getIdentifier(false, " with alias: ", "") << std::endl;
1526}
1527
1532#ifndef MAIA_DISABLE_STRUCTURED
1533template <MInt nDim>
1534void Application::createSolver(StructuredGrid<nDim>* grid, const MInt solverId, MBool* propertiesGroups,
1535 const MPI_Comm comm) {
1536 TRACE();
1537
1538
1539 // Determine solver type from property file
1540 const MString solverType = Context::getSolverProperty<MString>("solvertype", solverId, AT_);
1541
1542 // Now create the specified solver
1543 switch(string2enum(solverType)) {
1544 case MAIA_STRUCTURED: {
1545 m_solvers[solverId] =
1546 make_unique<typename FvStructuredSolverXD<nDim>::type>(solverId, grid, propertiesGroups, comm);
1547 break;
1548 }
1549 default: {
1550 TERMM(1, "Unknown solver type '" + solverType + "', exiting ... ");
1551 }
1552 }
1553
1554 m_log << "Created solver #" << std::to_string(solverId) << ": " << solverType
1555 << m_solvers[solverId]->getIdentifier(false, " with alias: ", "") << std::endl;
1556}
1557#endif
1558
1559
1561template <MInt nDim>
1562void Application::createSolver(const MInt solverId, const MPI_Comm comm) {
1563 TRACE();
1564
1565 // Determine solver type from property file
1566 const MString solverType = Context::getSolverProperty<MString>("solvertype", solverId, AT_);
1567
1568 switch(string2enum(solverType)) {
1569 case MAIA_ACOUSTIC_ANALOGY: {
1570 m_solvers[solverId] = make_unique<AcaSolver<nDim>>(solverId, comm);
1571 break;
1572 }
1573 default: {
1574 TERMM(1, "Unknown solver type '" + solverType + "', exiting ... ");
1575 }
1576 }
1577
1578 m_log << "Created solver #" << std::to_string(solverId) << ": " << solverType
1579 << m_solvers[solverId]->getIdentifier(false, " with alias: ", "") << std::endl;
1580}
1581
1582
1587template <MInt nDim>
1589 TRACE();
1590
1591 const MString couplerType = Context::getBasicProperty<MString>("couplerType_" + std::to_string(couplerId), AT_);
1592
1593 cerr0 << "=== Create coupler #" << couplerId << " " << couplerType << std::endl;
1594
1595 // Determine which solvers the coupler is supposed to couple
1596 // TODO labels:COUPLER allow more than 2 solvers to be coupled, e.g. for multilevel
1597 MInt solverToCoupleLength = Context::propertyLength("solversToCouple_" + std::to_string(couplerId));
1598 std::vector<MInt> solversToCouple;
1599 for(MInt solver = 0; solver < solverToCoupleLength; solver++) {
1600 solversToCouple.push_back(-1);
1601 if(Context::propertyExists("solversToCouple_" + std::to_string(couplerId))) {
1602 solversToCouple[solver] =
1603 Context::getBasicProperty<MInt>("solversToCouple_" + std::to_string(couplerId), AT_, nullptr, solver);
1604 if(solversToCouple[solver] < 0 || solversToCouple[solver] >= m_noSolvers) {
1605 TERMM(1, "Invalid solver id: " + std::to_string(solversToCouple[solver]));
1606 }
1607 } else {
1608 TERMM(1, "solversToCouple_" + std::to_string(couplerId) + " has to be specified!");
1609 }
1610 }
1611
1612 // Create the coupler
1613 //
1614 switch(string2enum(couplerType)) {
1615 case COUPLER_LB_DG_APE: {
1616 const MInt nDist = Context::getSolverProperty<MInt>("noDistributions", solversToCouple[0], AT_);
1617 switch(nDist) {
1618 case 19: {
1619 using SysEqnLb = lb::LbSysEqnIncompressible<3, 19>;
1620 const auto lbSolver = static_cast<LbSolverDxQy<3, 19, SysEqnLb>*>(m_solvers[solversToCouple[0]].get());
1621 const auto dgSolver =
1622 static_cast<DgCartesianSolver<3, DgSysEqnAcousticPerturb<3>>*>(m_solvers[solversToCouple[1]].get());
1623 m_couplers[couplerId] = make_unique<LbDgApe<3, 19, SysEqnLb>>(couplerId, lbSolver, dgSolver);
1624 break;
1625 }
1626 case 27: {
1627 using SysEqnLb = lb::LbSysEqnIncompressible<3, 27>;
1628 const auto lbSolver = static_cast<LbSolverDxQy<3, 27, SysEqnLb>*>(m_solvers[solversToCouple[0]].get());
1629 const auto dgSolver =
1630 static_cast<DgCartesianSolver<3, DgSysEqnAcousticPerturb<3>>*>(m_solvers[solversToCouple[1]].get());
1631 m_couplers[couplerId] = make_unique<LbDgApe<3, 27, SysEqnLb>>(couplerId, lbSolver, dgSolver);
1632 break;
1633 }
1634 default: {
1635 mTerm(1, "Unknown number of distributions! Only working for q19 and q27, yet.");
1636 }
1637 }
1638 break;
1639 }
1640 case COUPLER_LS_FV_MB: {
1641 MInt fvSystemEquations = string2enum("FV_SYSEQN_NS");
1642 if(Context::propertyExists("fvSystemEquations", solversToCouple[1])) {
1643 fvSystemEquations =
1644 string2enum(Context::getSolverProperty<MString>("fvSystemEquations", solversToCouple[1], AT_));
1645 }
1646 switch(fvSystemEquations) {
1647 case FV_SYSEQN_RANS: {
1648 m_couplers[couplerId] =
1649 make_unique<typename LsFvMbXD<nDim, FvSysEqnRANS<nDim, RANSModelConstants<RANS_SA_DV>>>::type>(
1650 couplerId,
1651 static_cast<typename LsCartesianSolverXD<nDim>::type*>(m_solvers[solversToCouple[0]].get()),
1653 m_solvers[solversToCouple[1]].get()));
1654 break;
1655 }
1656 case FV_SYSEQN_NS:
1657 default: {
1658 m_couplers[couplerId] = make_unique<typename LsFvMbXD<nDim, FvSysEqnNS<nDim>>::type>(
1659 couplerId,
1660 static_cast<typename LsCartesianSolverXD<nDim>::type*>(m_solvers[solversToCouple[0]].get()),
1661 static_cast<FvMbCartesianSolverXD<nDim, FvSysEqnNS<nDim>>*>(m_solvers[solversToCouple[1]].get()));
1662 break;
1663 }
1664 }
1665
1666 break;
1667 }
1668 case COUPLER_FV_ZONAL_RTV: {
1669 MString ransMethod = "";
1670 if(Context::propertyExists("ransMethod", solversToCouple[0])) {
1671 ransMethod = Context::getSolverProperty<MString>("ransMethod", solversToCouple[0], AT_);
1672 }
1673 switch(string2enum(ransMethod)) {
1674 case RANS_SA:
1675 case RANS_SA_DV: {
1676 m_couplers[couplerId] = make_unique<FvZonalRTV<nDim, FvSysEqnRANS<nDim, RANSModelConstants<RANS_SA_DV>>>>(
1677 couplerId,
1679 m_solvers[solversToCouple[0]].get()),
1680 static_cast<FvCartesianSolverXD<nDim, FvSysEqnNS<nDim>>*>(m_solvers[solversToCouple[1]].get()));
1681 break;
1682 }
1683 case RANS_FS: {
1684 m_couplers[couplerId] = make_unique<FvZonalRTV<nDim, FvSysEqnRANS<nDim, RANSModelConstants<RANS_FS>>>>(
1685 couplerId,
1687 m_solvers[solversToCouple[0]].get()),
1688 static_cast<FvCartesianSolverXD<nDim, FvSysEqnNS<nDim>>*>(m_solvers[solversToCouple[1]].get()));
1689 break;
1690 }
1691 default: {
1692 TERMM(1, "Unknown RANS model for solver " + to_string(solversToCouple[0]));
1693 }
1694 }
1695 break;
1696 }
1697 case COUPLER_FV_ZONAL_STG: {
1698 MString ransMethod = "";
1699 if(Context::propertyExists("ransMethod", solversToCouple[0])) {
1700 ransMethod = Context::getSolverProperty<MString>("ransMethod", solversToCouple[0], AT_);
1701 }
1702 switch(string2enum(ransMethod)) {
1703 case RANS_SA:
1704 case RANS_SA_DV: {
1705 m_couplers[couplerId] = make_unique<FvZonalSTG<nDim, FvSysEqnRANS<nDim, RANSModelConstants<RANS_SA_DV>>>>(
1706 couplerId,
1708 m_solvers[solversToCouple[0]].get()),
1709 static_cast<FvCartesianSolverXD<nDim, FvSysEqnNS<nDim>>*>(m_solvers[solversToCouple[1]].get()));
1710 break;
1711 }
1712 case RANS_FS: {
1713 m_couplers[couplerId] = make_unique<FvZonalSTG<nDim, FvSysEqnRANS<nDim, RANSModelConstants<RANS_FS>>>>(
1714 couplerId,
1716 m_solvers[solversToCouple[0]].get()),
1717 static_cast<FvCartesianSolverXD<nDim, FvSysEqnNS<nDim>>*>(m_solvers[solversToCouple[1]].get()));
1718 break;
1719 }
1720 default: {
1721 TERMM(1, "Unknown RANS model for solver " + to_string(solversToCouple[0]));
1722 }
1723 }
1724 break;
1725 }
1726 case COUPLER_FV_MB_ZONAL: {
1727 MInt fvSystemEquations = string2enum("FV_SYSEQN_NS");
1728 if(Context::propertyExists("fvSystemEquations", solversToCouple[1])) {
1729 fvSystemEquations =
1730 string2enum(Context::getSolverProperty<MString>("fvSystemEquations", solversToCouple[1], AT_));
1731 }
1732 switch(fvSystemEquations) {
1733 case FV_SYSEQN_RANS: {
1734 m_couplers[couplerId] =
1735 make_unique<CouplerFvMbZonal<nDim, FvSysEqnRANS<nDim, RANSModelConstants<RANS_SA_DV>>>>(
1736 couplerId,
1738 m_solvers[solversToCouple[0]].get()),
1740 m_solvers[solversToCouple[1]].get()));
1741 break;
1742 }
1743 case FV_SYSEQN_NS:
1744 default: {
1745 m_couplers[couplerId] = make_unique<CouplerFvMbZonal<nDim, FvSysEqnNS<nDim>>>(
1746 couplerId,
1747 static_cast<FvMbCartesianSolverXD<nDim, FvSysEqnNS<nDim>>*>(m_solvers[solversToCouple[0]].get()),
1748 static_cast<FvMbCartesianSolverXD<nDim, FvSysEqnNS<nDim>>*>(m_solvers[solversToCouple[1]].get()));
1749 break;
1750 }
1751 }
1752 break;
1753 }
1754
1756 MInt fvSystemEquations = string2enum("FV_SYSEQN_NS");
1757 if(Context::propertyExists("fvSystemEquations", solversToCouple[1])) {
1758 fvSystemEquations =
1759 string2enum(Context::getSolverProperty<MString>("fvSystemEquations", solversToCouple[1], AT_));
1760 }
1761 switch(fvSystemEquations) {
1762 case FV_SYSEQN_RANS: {
1763 m_couplers[couplerId] =
1764 make_unique<FvCartesianInterpolation<nDim, FvSysEqnRANS<nDim, RANSModelConstants<RANS_SA_DV>>,
1766 couplerId,
1768 m_solvers[solversToCouple[0]].get()),
1770 m_solvers[solversToCouple[1]].get()));
1771 break;
1772 }
1773 case FV_SYSEQN_NS:
1774 default: {
1775 m_couplers[couplerId] = make_unique<
1777 couplerId,
1779 m_solvers[solversToCouple[0]].get()),
1780 static_cast<FvCartesianSolverXD<nDim, FvSysEqnNS<nDim>>*>(m_solvers[solversToCouple[1]].get()));
1781 break;
1782 }
1783 }
1784 break;
1785 }
1786
1787 case COUPLER_FV_MULTILEVEL: {
1788 // Note: couple all solvers (FV) in a multilevel computation
1789 auto fvSolvers = std::vector<FvCartesianSolverXD<nDim, FvSysEqnNS<nDim>>*>{};
1790 for(MInt s = 0; s < (MInt)solversToCouple.size(); s++) {
1791 fvSolvers.push_back(
1792 static_cast<FvCartesianSolverXD<nDim, FvSysEqnNS<nDim>>*>(m_solvers[solversToCouple[s]].get()));
1793 }
1794 m_couplers[couplerId] = make_unique<CouplerFvMultilevel<nDim, FvSysEqnNS<nDim>>>(couplerId, fvSolvers);
1795
1796 break;
1797 }
1798
1800 // Multilevel interpolation: use coarse grid restart and interpolate it onto the finer grid(s)/solver(s)
1801 auto fvSolvers = std::vector<FvCartesianSolverXD<nDim, FvSysEqnNS<nDim>>*>{};
1802 for(MInt s = 0; s < (MInt)solversToCouple.size(); s++) {
1803 fvSolvers.push_back(
1804 static_cast<FvCartesianSolverXD<nDim, FvSysEqnNS<nDim>>*>(m_solvers[solversToCouple[s]].get()));
1805 }
1806 m_couplers[couplerId] =
1807 make_unique<CouplerFvMultilevelInterpolation<nDim, FvSysEqnNS<nDim>>>(couplerId, fvSolvers);
1808 break;
1809 }
1810
1811 case COUPLER_FV_DG_APE: {
1812 m_couplers[couplerId] = make_unique<DgCcAcousticPerturb<nDim, FvSysEqnNS<nDim>>>(
1813 couplerId,
1814 static_cast<FvCartesianSolverXD<nDim, FvSysEqnNS<nDim>>*>(m_solvers[solversToCouple[0]].get()),
1815 static_cast<DgCartesianSolver<nDim, DgSysEqnAcousticPerturb<nDim>>*>(m_solvers[solversToCouple[1]].get()));
1816 break;
1817 }
1818 case COUPLER_LS_LB: {
1819 MInt nDist = 27;
1820 nDist = Context::getSolverProperty<MInt>("noDistributions", solversToCouple[1], AT_, &nDist);
1821
1822 switch(nDist) {
1823 case 9: {
1824 auto lsSolver = static_cast<typename LsCartesianSolverXD<2>::type*>(m_solvers[solversToCouple[0]].get());
1825 using SysEqnLb = lb::LbSysEqnIncompressible<2, 9>;
1826 auto lbSolver = static_cast<LbSolverDxQy<2, 9, SysEqnLb>*>(m_solvers[solversToCouple[1]].get());
1827 m_couplers[couplerId] = make_unique<LsLb<2, 9, SysEqnLb>>(couplerId, lsSolver, lbSolver);
1828
1829 break;
1830 }
1831 case 19: {
1832 auto lsSolver = static_cast<typename LsCartesianSolverXD<3>::type*>(m_solvers[solversToCouple[0]].get());
1833 using SysEqnLb = lb::LbSysEqnIncompressible<3, 19>;
1834 auto lbSolver = static_cast<LbSolverDxQy<3, 19, SysEqnLb>*>(m_solvers[solversToCouple[1]].get());
1835 m_couplers[couplerId] = make_unique<LsLb<3, 19, SysEqnLb>>(couplerId, lsSolver, lbSolver);
1836
1837 break;
1838 }
1839 case 27: {
1840 auto lsSolver = static_cast<typename LsCartesianSolverXD<3>::type*>(m_solvers[solversToCouple[0]].get());
1841 using SysEqnLb = lb::LbSysEqnIncompressible<3, 27>;
1842 auto lbSolver = static_cast<LbSolverDxQy<3, 27, SysEqnLb>*>(m_solvers[solversToCouple[1]].get());
1843 m_couplers[couplerId] = make_unique<LsLb<3, 27, SysEqnLb>>(couplerId, lsSolver, lbSolver);
1844
1845 break;
1846 }
1847 default: {
1848 mTerm(1, "Unknown number of distributions!");
1849 }
1850 }
1851
1852 break;
1853 }
1854
1855 case COUPLER_LB_RB: {
1856 MInt nDist = 27;
1857 nDist = Context::getSolverProperty<MInt>("noDistributions", solversToCouple[0], AT_, &nDist);
1858
1859 switch(nDist) {
1860 case 9: {
1861 using SysEqnLb = lb::LbSysEqnIncompressible<2, 9>;
1862 auto lbSolver = static_cast<LbSolverDxQy<2, 9, SysEqnLb>*>(m_solvers[solversToCouple[0]].get());
1863 auto rigidBodies = static_cast<RigidBodies<2>*>(m_solvers[solversToCouple[1]].get());
1864 m_couplers[couplerId] = make_unique<LbRb<2, 9, SysEqnLb>>(couplerId, lbSolver, rigidBodies);
1865
1866 break;
1867 }
1868 case 19: {
1869 using SysEqnLb = lb::LbSysEqnIncompressible<3, 19>;
1870 auto lbSolver = static_cast<LbSolverDxQy<3, 19, SysEqnLb>*>(m_solvers[solversToCouple[0]].get());
1871 auto rigidBodies = static_cast<RigidBodies<3>*>(m_solvers[solversToCouple[1]].get());
1872 m_couplers[couplerId] = make_unique<LbRb<3, 19, SysEqnLb>>(couplerId, lbSolver, rigidBodies);
1873
1874 break;
1875 }
1876 case 27: {
1877 using SysEqnLb = lb::LbSysEqnIncompressible<3, 27>;
1878 auto lbSolver = static_cast<LbSolverDxQy<3, 27, SysEqnLb>*>(m_solvers[solversToCouple[0]].get());
1879 auto rigidBodies = static_cast<RigidBodies<3>*>(m_solvers[solversToCouple[1]].get());
1880 m_couplers[couplerId] = make_unique<LbRb<3, 27, SysEqnLb>>(couplerId, lbSolver, rigidBodies);
1881
1882 break;
1883 }
1884 default: {
1885 mTerm(1, "Unknown number of distributions!");
1886 }
1887 }
1888 break;
1889 }
1890
1891 case COUPLER_LB_LPT: {
1892 MInt nDist = 27;
1893 nDist = Context::getSolverProperty<MInt>("noDistributions", solversToCouple[1], AT_, &nDist);
1894
1895 switch(nDist) {
1896 case 9: {
1897 IF_CONSTEXPR(nDim == 3) { mTerm(1, "LPT not supported in 2D!"); }
1898 break;
1899 }
1900 case 19: {
1901 using SysEqnLb = lb::LbSysEqnIncompressible<3, 19>;
1902 auto lbSolver = static_cast<LbSolverDxQy<3, 19, SysEqnLb>*>(m_solvers[solversToCouple[0]].get());
1903 auto particleSolver = static_cast<LPT<3>*>(m_solvers[solversToCouple[1]].get());
1904 m_couplers[couplerId] = make_unique<LbLpt<3, 19, SysEqnLb>>(couplerId, particleSolver, lbSolver);
1905
1906 break;
1907 }
1908 case 27: {
1909 using SysEqnLb = lb::LbSysEqnIncompressible<3, 27>;
1910 auto lbSolver = static_cast<LbSolverDxQy<3, 27, SysEqnLb>*>(m_solvers[solversToCouple[0]].get());
1911 auto particleSolver = static_cast<LPT<3>*>(m_solvers[solversToCouple[1]].get());
1912 m_couplers[couplerId] = make_unique<LbLpt<3, 27, SysEqnLb>>(couplerId, particleSolver, lbSolver);
1913
1914 break;
1915 }
1916 default: {
1917 mTerm(1, "Unknown number of distributions!");
1918 }
1919 }
1920 break;
1921 }
1922
1923 case COUPLER_LS_LB_SURFACE: {
1924 MInt nDist = 27;
1925 nDist = Context::getSolverProperty<MInt>("noDistributions", solversToCouple[1], AT_, &nDist);
1926
1927 switch(nDist) {
1928 case 9: {
1929 auto lsSolver = static_cast<typename LsCartesianSolverXD<2>::type*>(m_solvers[solversToCouple[0]].get());
1930 using SysEqnLb = lb::LbSysEqnIncompressible<2, 9>;
1931 auto lbSolver = static_cast<LbSolverDxQy<2, 9, SysEqnLb>*>(m_solvers[solversToCouple[1]].get());
1932 m_couplers[couplerId] = make_unique<LsLbSurface<2, 9, SysEqnLb>>(couplerId, lsSolver, lbSolver);
1933
1934 break;
1935 }
1936 case 19: {
1937 auto lsSolver = static_cast<typename LsCartesianSolverXD<3>::type*>(m_solvers[solversToCouple[0]].get());
1938 using SysEqnLb = lb::LbSysEqnIncompressible<3, 19>;
1939 auto lbSolver = static_cast<LbSolverDxQy<3, 19, SysEqnLb>*>(m_solvers[solversToCouple[1]].get());
1940 m_couplers[couplerId] = make_unique<LsLbSurface<3, 19, SysEqnLb>>(couplerId, lsSolver, lbSolver);
1941
1942 break;
1943 }
1944 case 27: {
1945 auto lsSolver = static_cast<typename LsCartesianSolverXD<3>::type*>(m_solvers[solversToCouple[0]].get());
1946 using SysEqnLb = lb::LbSysEqnIncompressible<3, 27>;
1947 auto lbSolver = static_cast<LbSolverDxQy<3, 27, SysEqnLb>*>(m_solvers[solversToCouple[1]].get());
1948 m_couplers[couplerId] = make_unique<LsLbSurface<3, 27, SysEqnLb>>(couplerId, lsSolver, lbSolver);
1949
1950 break;
1951 }
1952 default: {
1953 mTerm(1, "Unknown number of distributions!");
1954 }
1955 }
1956
1957 break;
1958 }
1959
1960 case COUPLER_LS_FV: {
1961 auto lsSolver = static_cast<typename LsCartesianSolverXD<nDim>::type*>(m_solvers[solversToCouple[0]].get());
1962 MInt fvSystemEquations = string2enum("FV_SYSEQN_NS");
1963 if(Context::propertyExists("fvSystemEquations", solversToCouple[1])) {
1964 fvSystemEquations =
1965 string2enum(Context::getSolverProperty<MString>("fvSystemEquations", solversToCouple[1], AT_));
1966 }
1967 switch(fvSystemEquations) {
1968 case FV_SYSEQN_RANS: {
1970 m_solvers[solversToCouple[1]]
1971 .get();
1972 m_couplers[couplerId] =
1973 make_unique<typename CouplingLsFvXD<nDim, FvSysEqnRANS<nDim, RANSModelConstants<RANS_SA_DV>>>::type>(
1974 couplerId, lsSolver, fvSolvers);
1975 break;
1976 }
1977 default: {
1978 auto fvSolvers = (FvCartesianSolverXD<nDim, FvSysEqnNS<nDim>>*)m_solvers[solversToCouple[1]].get();
1979 m_couplers[couplerId] =
1980 make_unique<typename CouplingLsFvXD<nDim, FvSysEqnNS<nDim>>::type>(couplerId, lsSolver, fvSolvers);
1981 }
1982 }
1983
1984 break;
1985 }
1986
1988 auto lsSolverId = solversToCouple[0];
1989 auto fvSolverId = solversToCouple[1];
1990
1991 m_couplers[couplerId] = make_unique<typename LsFvCombustionXD<nDim, FvSysEqnNS<nDim>>::type>(
1992 couplerId,
1993 static_cast<typename LsCartesianSolverXD<nDim>::type*>(m_solvers[lsSolverId].get()),
1994 static_cast<FvCartesianSolverXD<nDim, FvSysEqnNS<nDim>>*>(m_solvers[fvSolverId].get()));
1995 break;
1996 }
1997
1999 MInt fvSystemEquations = string2enum("FV_SYSEQN_NS");
2000 if(Context::propertyExists("fvSystemEquations", solversToCouple[1])) {
2001 fvSystemEquations =
2002 string2enum(Context::getSolverProperty<MString>("fvSystemEquations", solversToCouple[1], AT_));
2003 }
2004 if(nDim != 3) mTerm(1, AT_, "LB-FV-Euler-Euler-Multiphase only implemented for nDim = 3");
2005
2006 switch(fvSystemEquations) {
2007 case FV_SYSEQN_RANS: {
2008 mTerm(1, AT_, "RANS not supported in combination with LB-FV-EE-Multiphase!");
2009 break;
2010 }
2011 case FV_SYSEQN_EEGAS: {
2012 MInt nDist = 27;
2013 nDist = Context::getSolverProperty<MInt>("noDistributions", solversToCouple[0], AT_, &nDist);
2014
2015 switch(nDist) {
2016 case 9: {
2017 mTerm(1, "nDist = 9 not supported with EE Multiphase!");
2018
2019 break;
2020 }
2021 case 19: {
2022 using SysEqnLb = lb::LbSysEqnIncompressible<3, 19>;
2023 auto lbSolver = static_cast<LbSolverDxQy<3, 19, SysEqnLb>*>(m_solvers[solversToCouple[0]].get());
2024 auto fvSolver =
2025 static_cast<FvCartesianSolverXD<3, FvSysEqnEEGas<3>>*>(m_solvers[solversToCouple[1]].get());
2026
2027 m_couplers[couplerId] = make_unique<CouplerLbFvEEMultiphase<3, 19, SysEqnLb, FvSysEqnEEGas<3>>>(
2028 couplerId, lbSolver, fvSolver);
2029
2030 break;
2031 }
2032 case 27: {
2033 using SysEqnLb = lb::LbSysEqnIncompressible<3, 27>;
2034 auto lbSolver = static_cast<LbSolverDxQy<3, 27, SysEqnLb>*>(m_solvers[solversToCouple[0]].get());
2035 auto fvSolver =
2036 static_cast<FvCartesianSolverXD<3, FvSysEqnEEGas<3>>*>(m_solvers[solversToCouple[1]].get());
2037
2038 m_couplers[couplerId] = make_unique<CouplerLbFvEEMultiphase<3, 27, SysEqnLb, FvSysEqnEEGas<3>>>(
2039 couplerId, lbSolver, fvSolver);
2040
2041 break;
2042 }
2043 default: {
2044 mTerm(1, "Unknown number of distributions!");
2045 }
2046 }
2047 break;
2048 }
2049 case FV_SYSEQN_NS:
2050 default: {
2051 mTerm(1, AT_, "This SysEqn is not supported in combination with LB-FV-EE-Multiphase!");
2052 break;
2053 }
2054 }
2055 break;
2056 }
2057
2058 case COUPLER_LB_LB: {
2059 MInt nDist = 27;
2060 nDist = Context::getSolverProperty<MInt>("noDistributions", solversToCouple[0], AT_, &nDist);
2061 {
2062 const MInt tempNDist = Context::getSolverProperty<MInt>("noDistributions", solversToCouple[1], AT_, &nDist);
2063 if(nDist != tempNDist) mTerm(1, AT_, "Can't couple LB solvers with different noDistributions!");
2064 }
2065 switch(nDist) {
2066 case 9: {
2067 using SysEqnLb = lb::LbSysEqnIncompressible<2, 9>;
2068 std::vector<LbSolverDxQy<2, 9, SysEqnLb>*> lbSolvers;
2069 lbSolvers.push_back(static_cast<LbSolverDxQy<2, 9, SysEqnLb>*>(m_solvers[solversToCouple[0]].get()));
2070 lbSolvers.push_back(static_cast<LbSolverDxQy<2, 9, SysEqnLb>*>(m_solvers[solversToCouple[1]].get()));
2071 m_couplers[couplerId] = make_unique<CouplerLbLb<2, 9, SysEqnLb>>(couplerId, lbSolvers);
2072 break;
2073 }
2074 case 19: {
2075 using SysEqnLb = lb::LbSysEqnIncompressible<3, 19>;
2076 std::vector<LbSolverDxQy<3, 19, SysEqnLb>*> lbSolvers;
2077 lbSolvers.push_back(static_cast<LbSolverDxQy<3, 19, SysEqnLb>*>(m_solvers[solversToCouple[0]].get()));
2078 lbSolvers.push_back(static_cast<LbSolverDxQy<3, 19, SysEqnLb>*>(m_solvers[solversToCouple[1]].get()));
2079 m_couplers[couplerId] = make_unique<CouplerLbLb<3, 19, SysEqnLb>>(couplerId, lbSolvers);
2080 break;
2081 }
2082 case 27: {
2083 using SysEqnLb = lb::LbSysEqnIncompressible<3, 27>;
2084 std::vector<LbSolverDxQy<3, 27, SysEqnLb>*> lbSolvers;
2085 lbSolvers.push_back(static_cast<LbSolverDxQy<3, 27, SysEqnLb>*>(m_solvers[solversToCouple[0]].get()));
2086 lbSolvers.push_back(static_cast<LbSolverDxQy<3, 27, SysEqnLb>*>(m_solvers[solversToCouple[1]].get()));
2087 m_couplers[couplerId] = make_unique<CouplerLbLb<3, 27, SysEqnLb>>(couplerId, lbSolvers);
2088 break;
2089 }
2090 default: {
2091 mTerm(1, "Unknown number of distributions!");
2092 }
2093 }
2094 break;
2095 }
2096
2097 case COUPLER_FV_PARTICLE: {
2098 auto particleSolver = static_cast<LPT<nDim>*>(m_solvers[solversToCouple[1]].get());
2099 MInt fvSystemEquations = string2enum("FV_SYSEQN_NS");
2100 if(Context::propertyExists("fvSystemEquations", solversToCouple[1])) {
2101 fvSystemEquations =
2102 string2enum(Context::getSolverProperty<MString>("fvSystemEquations", solversToCouple[1], AT_));
2103 }
2104 switch(fvSystemEquations) {
2105 case FV_SYSEQN_RANS: {
2107 m_solvers[solversToCouple[0]].get());
2108 if(nDim == 3) {
2109 m_couplers[couplerId] =
2110 make_unique<CouplerFvParticle<nDim, FvSysEqnRANS<nDim, RANSModelConstants<RANS_SA_DV>>>>(
2111 couplerId, particleSolver, fvSolver);
2112 } else {
2113 mTerm(1, AT_, "FV Particle not supported in 2D!");
2114 }
2115 break;
2116 }
2117 case FV_SYSEQN_NS:
2118 default: {
2119 auto fvSolver =
2120 static_cast<FvCartesianSolverXD<nDim, FvSysEqnNS<nDim>>*>(m_solvers[solversToCouple[0]].get());
2121 if(nDim == 3) {
2122 m_couplers[couplerId] =
2123 make_unique<CouplerFvParticle<nDim, FvSysEqnNS<nDim>>>(couplerId, particleSolver, fvSolver);
2124 } else {
2125 mTerm(1, AT_, "FV Particle not supported in 2D!");
2126 }
2127
2128 break;
2129 }
2130 }
2131 break;
2132 }
2133
2134 default: {
2135 TERMM(1, "Unknown coupler type '" + couplerType + "', exiting ... ");
2136 }
2137 }
2138
2139 m_log << "Created coupler #" << std::to_string(couplerId) << ": " << couplerType << " for solvers";
2140 for(MInt solver = 0; solver < 2; solver++) {
2141 m_log << " " << solversToCouple[solver];
2142 }
2143 m_log << std::endl;
2144}
2145
2146
2152 TRACE();
2153
2154 ExecutionRecipe* recipe = nullptr;
2155
2156 const MString recipeType = Context::getBasicProperty<MString>("executionRecipe", AT_);
2157
2158 switch(string2enum(recipeType)) {
2159 case RECIPE_BASE: {
2160 recipe = new ExecutionRecipe(&m_solvers, &m_couplers);
2161 break;
2162 }
2163 case RECIPE_INTRASTEP: {
2165 break;
2166 }
2167 case RECIPE_ITERATION: {
2169 break;
2170 }
2171 default: {
2172 TERMM(1, "Unknown execution recipe '" + recipeType + "', exiting ... ");
2173 }
2174 }
2175
2176 m_log << "Created execution recipe: " << recipeType << " for " << m_noSolvers << " solvers" << std::endl;
2177
2178 return recipe;
2179}
2180
2185template <MInt nDim>
2187 TRACE();
2188
2189 PostProcessingInterface* pp = nullptr;
2190
2191 const MString postprocessingType =
2192 Context::getBasicProperty<MString>("postProcessingType_" + std::to_string(postprocessingId), AT_);
2193
2194 // FIXME labels:PP,DOC read with _$postprocessingId and allow for multiple postProcessingSolverIds
2195 // to specify the second/third solver Ids in coupled cases!
2196 const MInt postprocessingSolverId =
2197 Context::getBasicProperty<MInt>("postProcessingSolverIds", AT_, nullptr, postprocessingId);
2198
2199 PostData<nDim>* postDataPointer = nullptr;
2200 // postprocessing for special output that does not need a PostData Solver
2201 if(m_postDataSolverId == -1) {
2202 if(globalDomainId() == 0)
2203 cerr << "\033[0;31m#### WARNING:\033[0m You are using a postprocessing routine without a PostData Solver!"
2204 << endl;
2205 m_postDataSolverId = postprocessingSolverId;
2206 } else {
2207 postDataPointer = static_cast<PostData<nDim>*>(m_solvers[m_postDataSolverId].get());
2208 }
2209
2210 // Create the PostProcessing
2211 //
2212 switch(string2enum(postprocessingType)) {
2213 case POSTPROCESSING_FV: {
2214 MInt fvSystemEquations = string2enum("FV_SYSEQN_NS");
2215 if(Context::propertyExists("fvSystemEquations", postprocessingSolverId)) {
2216 fvSystemEquations =
2217 string2enum(Context::getSolverProperty<MString>("fvSystemEquations", postprocessingSolverId, AT_));
2218 }
2219 switch(fvSystemEquations) {
2220 case FV_SYSEQN_RANS: {
2222 postprocessingId,
2223 postDataPointer,
2225 m_solvers[postprocessingSolverId].get()));
2226 break;
2227 }
2228 case FV_SYSEQN_EEGAS: {
2229 IF_CONSTEXPR(nDim == 2)
2230 mTerm(1, AT_, "FVSysEqnEEGas is not tested for 2D at all and probably does not make much sense!");
2232 postprocessingId,
2233 postDataPointer,
2234 static_cast<FvCartesianSolverXD<nDim, FvSysEqnEEGas<nDim>>*>(m_solvers[postprocessingSolverId].get()));
2235 break;
2236 }
2237 case FV_SYSEQN_NS: {
2239 postprocessingId,
2240 postDataPointer,
2241 static_cast<FvCartesianSolverXD<nDim, FvSysEqnNS<nDim>>*>(m_solvers[postprocessingSolverId].get()));
2242 break;
2243 }
2244 case FV_SYSEQN_DETCHEM: {
2246 postprocessingId,
2247 static_cast<PostData<nDim>*>(m_solvers[m_postDataSolverId].get()),
2248 static_cast<FvCartesianSolverXD<nDim, FvSysEqnDetChem<nDim>>*>(m_solvers[postprocessingSolverId].get()));
2249 break;
2250 }
2251 default:
2252 TERMM(1, "Unsupported system of equations.");
2253 }
2254 break;
2255 }
2256 case POSTPROCESSING_DG: {
2257 const MInt dgSystemEquations =
2258 string2enum(Context::getSolverProperty<MString>("dgSystemEquations", postprocessingSolverId, AT_));
2259 switch(dgSystemEquations) {
2262 postprocessingId,
2263 postDataPointer,
2265 m_solvers[postprocessingSolverId].get()));
2266 break;
2267 }
2270 postprocessingId,
2271 postDataPointer,
2273 m_solvers[postprocessingSolverId].get()));
2274 break;
2275 }
2276 default:
2277 TERMM(1, "Unsupported system of equations.");
2278 }
2279 break;
2280 }
2281 case POSTPROCESSING_LB: {
2282 pp = new PostProcessingLb<nDim>(postprocessingId, postDataPointer,
2283 static_cast<LbSolver<nDim>*>(m_solvers[postprocessingSolverId].get()));
2284 break;
2285 }
2286 case POSTPROCESSING_FVLPT: {
2287 MInt fvSystemEquations = string2enum("FV_SYSEQN_NS");
2288 if(Context::propertyExists("fvSystemEquations", postprocessingSolverId)) {
2289 fvSystemEquations =
2290 string2enum(Context::getSolverProperty<MString>("fvSystemEquations", postprocessingSolverId, AT_));
2291 }
2292 switch(fvSystemEquations) {
2293 case FV_SYSEQN_RANS: {
2294 if(nDim == 3) {
2296 postprocessingId,
2297 postDataPointer,
2299 m_solvers[postprocessingSolverId].get()),
2300 static_cast<LPT<nDim>*>(m_solvers[postprocessingSolverId + 1].get()));
2301 } else {
2302 mTerm(1, AT_, "LPT not supported in 2D!");
2303 }
2304 break;
2305 }
2306 case FV_SYSEQN_NS: {
2307 if(nDim == 3) {
2309 postprocessingId,
2310 postDataPointer,
2311 static_cast<FvCartesianSolverXD<nDim, FvSysEqnNS<nDim>>*>(m_solvers[postprocessingSolverId].get()),
2312 static_cast<LPT<nDim>*>(m_solvers[postprocessingSolverId + 1].get()));
2313 } else {
2314 mTerm(1, AT_, "LPT not supported in 2D!");
2315 }
2316 break;
2317 }
2318 default:
2319 TERMM(1, "Unsupported system of equations.");
2320 }
2321 break;
2322 }
2323 case POSTPROCESSING_LBLPT: {
2324 if(nDim == 3) {
2325 pp = new PostProcessingLbLPT<nDim>(postprocessingId,
2326 postDataPointer,
2327 static_cast<LbSolver<nDim>*>(m_solvers[postprocessingSolverId].get()),
2328 static_cast<LPT<nDim>*>(m_solvers[postprocessingSolverId + 1].get()));
2329 } else {
2330 mTerm(1, AT_, "LPT not supported in 2D!");
2331 }
2332 break;
2333 }
2334 default: {
2335 TERMM(1, "Unknown postprocessing type '" + postprocessingType + "', exiting ... ");
2336 }
2337 }
2338
2339 m_log << "Created postprocessing #" << std::to_string(postprocessingId) << ": " << postprocessingType << " for solver"
2340 << " " << postprocessingSolverId << std::endl;
2341
2342 return pp;
2343}
2344
2347 // Return if not enabled
2349 return;
2350 }
2351
2352 const MBool isSamplingStep = (globalTimeStep % m_solverTimingsSampleInterval == 0);
2353 const MInt noSolversAndCouplers = m_noSolvers + m_noCouplers;
2354 const MBool allTimings = m_writeAllSolverTimings;
2355
2356 if(isSamplingStep) {
2357 // Store time step
2359
2360 // TODO labels:TIMERS store domainInfo for each sampling time step/for each changed domain decomposition?
2361 // Determine domain decomposition information of each solver
2362 m_domainInfo.clear();
2363 for(MInt solverId = 0; solverId < m_noSolvers; solverId++) {
2364 m_solvers[solverId]->getDomainDecompositionInformation(m_domainInfo);
2365 }
2366 for(MInt i = 0; i < m_noCouplers; i++) {
2367 m_couplers[i]->getDomainDecompositionInformation(m_domainInfo);
2368 }
2369 }
2370
2371 // TODO labels:TIMERS if a sample interval N > 1 is given, just sample every N-th step (current status ) or
2372 // compute an average? Note: for computing an average the number of timings might not correspond
2373 // to the sample-interval
2374 MInt timerIndex = 0;
2375 for(MInt j = 0; j < noSolversAndCouplers; j++) {
2376 const MBool isSolver = (j < m_noSolvers);
2377 const MInt noTimers = (isSolver) ? m_solvers[j]->noSolverTimers(allTimings)
2378 : m_couplers[j - m_noSolvers]->noCouplingTimers(allTimings);
2379
2380 // Get timing records of solver/coupler
2381 std::vector<std::pair<MString, MFloat>> timings{};
2382 (isSolver) ? m_solvers[j]->getSolverTimings(timings, allTimings)
2383 : m_couplers[j - m_noSolvers]->getCouplingTimings(timings, allTimings);
2384
2385 if((MInt)timings.size() != noTimers) {
2386 TERMM(1, "Wrong number of solver timings returned by getSolverTimings(): is " + std::to_string(timings.size())
2387 + ", should be " + std::to_string(noTimers));
2388 }
2389
2390 for(MInt i = 0; i < noTimers; i++) {
2391 const MFloat timing = timings[i].second;
2392 const MString name = timings[i].first;
2393 // Compute time difference
2394 MFloat diff = timing - m_solverTimingsPrevTime[timerIndex];
2395
2396 if(name != m_solverTimingsNames[timerIndex]) {
2397 TERMM(1, "Timer name does not match.");
2398 }
2399
2400 // This happens if the DLB timers were reset from the gridcontroller
2401 if(diff < 0.0) {
2402 diff = timing;
2403 }
2404
2405 // Only store timing if it should be written to the timings file
2406 if(isSamplingStep) {
2407 m_solverTimings[timerIndex].push_back(diff);
2408 }
2409
2410 m_solverTimingsPrevTime[timerIndex] = timing;
2411 timerIndex++;
2412 }
2413 }
2414
2415 // Store timings if this is the final time step or a timings write time step
2416 storeTimingsAndSolverInformation(finalTimeStep);
2417}
2418
2419
2422 TRACE();
2423 using namespace maia::parallel_io;
2424
2425 // Return if not enabled
2427 return;
2428 }
2429
2430 // Check if timings should be written at this step
2431 const MBool writeStep = (m_solverTimingsWriteInterval > 0)
2432 ? (globalTimeStep % m_solverTimingsWriteInterval == 0 || finalTimeStep)
2433 : finalTimeStep;
2434 if(!writeStep) {
2435 return;
2436 }
2437
2438 const MInt noValues = m_solverTimings.size();
2439 if(noValues == 0) {
2440 return;
2441 }
2442 const MInt noTimings = m_solverTimings[0].size();
2443 if(noTimings == 0) {
2444 return;
2445 }
2446
2447 // Timings output file name
2448 stringstream fileName;
2449 fileName << "solverTimings_n" << globalNoDomains() << "_" << globalTimeStep << ParallelIo::fileExt();
2450
2451 // check for existing file
2452 if(globalDomainId() == 0) {
2453 ifstream readFile;
2454 readFile.open(fileName.str());
2455 if(readFile) {
2456 stringstream fileNameNew;
2457 fileNameNew << "solverTimings_n" << globalNoDomains() << "_" << globalTimeStep << "_bu" << ParallelIo::fileExt();
2458 std::rename(fileName.str().c_str(), fileNameNew.str().c_str());
2459 }
2460 }
2461
2462 ParallelIo file(fileName.str(), PIO_REPLACE, MPI_COMM_WORLD);
2463 file.defineArray(PIO_INT, "timeStep", noTimings);
2464
2465 const MInt noInfo = m_domainInfo.size();
2466
2467 // TODO labels:TIMERS store domainInfo for each changed configuration when using DLB?
2468 // Domain information
2469 ParallelIo::size_type dimSizesInfo[] = {globalNoDomains(), noInfo};
2470 file.defineArray(PIO_INT, "domainInfo", 2, &dimSizesInfo[0]);
2471 file.setAttribute("domain index", "dim_0", "domainInfo");
2472 file.setAttribute("information index", "dim_1", "domainInfo");
2473
2474 for(MInt i = 0; i < noInfo; i++) {
2475 std::stringstream var;
2476 var << "var_" << i;
2477 file.setAttribute(m_domainInfo[i].first, var.str(), "domainInfo");
2478 }
2479
2480 // Dimensions of timings: noDomains x noTimings x noValues
2481 ParallelIo::size_type dimSizesTimings[] = {globalNoDomains(), noTimings, noValues};
2482
2483 file.defineArray(PIO_FLOAT, "timings", 3, &dimSizesTimings[0]);
2484
2485 file.setAttribute("domain index", "dim_0", "timings");
2486 file.setAttribute("time step index", "dim_1", "timings");
2487 file.setAttribute("timings index", "dim_2", "timings");
2488
2489 for(MInt i = 0; i < noValues; i++) {
2490 std::stringstream var;
2491 var << "var_" << i;
2492 file.setAttribute(m_solverTimingsNames[i], var.str(), "timings");
2493 }
2494
2495 // Assemble domain information
2496 MFloatScratchSpace info(noInfo, AT_, "data");
2497 for(MInt i = 0; i < noInfo; i++) {
2498 info[i] = m_domainInfo[i].second;
2499 }
2500
2501 // Assemble timings
2502 MFloatScratchSpace data(noTimings, noValues, AT_, "data");
2503 for(MInt i = 0; i < noTimings; i++) {
2504 for(MInt j = 0; j < noValues; j++) {
2505 data(i, j) = m_solverTimings[j][i];
2506 }
2507 }
2508
2509 // root writes timestep data
2510 if(globalDomainId() == 0) {
2511 file.setOffset(noTimings, 0);
2512 } else {
2513 file.setOffset(0, 0);
2514 }
2515 file.writeArray(&m_solverTimingsTimeStep[0], "timeStep");
2516
2517 // Write domain information
2518 file.setOffset(1, globalDomainId(), 2);
2519 file.writeArray(&info[0], "domainInfo");
2520
2521 // Write timings of all domains
2522 file.setOffset(1, globalDomainId(), 3);
2523 file.writeArray(&data[0], "timings");
2524
2525
2526 // Clear collected timings
2527 for(MInt timerId = 0; timerId < m_noGlobalSolverTimers; timerId++) {
2528 m_solverTimings[timerId].clear();
2530 }
2531}
2532
2535 TRACE();
2536
2537 // Clean up
2538 for(MInt i = 0; i < m_noSolvers; i++) {
2539 m_solvers[i]->cleanUp();
2540 }
2541 for(auto&& coupler : m_couplers) {
2542 coupler->cleanUp();
2543 }
2544}
2545
2546template void Application::run<2>();
2547template void Application::run<3>();
std::vector< MInt > m_solverTimingsTimeStep
Definition: application.h:117
MInt m_noGlobalSolverTimers
Definition: application.h:113
MInt gridType(const MString solverType)
Return the type of grid for a given solver type.
std::vector< MString > m_solverTimingsNames
Definition: application.h:118
MInt m_restartBackupInterval
The number of timesteps before executing a restart-backup.
Definition: application.h:80
MBool m_writeAllSolverTimings
Switch timings mode between ALL timings (default) and a reduced/essential timings mode.
Definition: application.h:108
std::vector< std::unique_ptr< Solver > > m_solvers
The list of solvers.
Definition: application.h:84
void cleanUp()
call cleanup functions in all solvers and couplers before returning from the application
ExecutionRecipe * createRecipe()
This function handels the creation of the execution recipe.
static MBool * readPropertiesGroups()
Reads in the properties groups.
void collectTimingsAndSolverInformation(const MBool finalTimeStep)
Collect the timings of all solvers and domain decomposition information.
MInt m_solverTimingsWriteInterval
Write interval for timings.
Definition: application.h:110
MBool m_ppAfterTS
post-processing in-solve position
Definition: application.h:100
std::vector< std::unique_ptr< Coupling > > m_couplers
The list of couplers.
Definition: application.h:90
MBool m_dualTimeStepping
Definition: application.h:76
std::vector< MFloat > m_solverTimingsPrevTime
Definition: application.h:116
MInt m_solverTimingsSampleInterval
Sampling interval for timings.
Definition: application.h:112
MInt m_noPostProcessing
The number of postprocessing solvers.
Definition: application.h:92
MInt m_maxIterations
Maximum number of iterations.
Definition: application.h:78
MBool m_initialAdaptation
Initial adaptation.
Definition: application.h:86
void createCoupler(MInt)
This function handels the creation of new couplers.
std::vector< std::vector< MFloat > > m_solverTimings
Definition: application.h:115
MBool m_displayMemoryStatistics
Memory statistics controller.
Definition: application.h:98
MInt m_noCouplers
The number of couplers.
Definition: application.h:88
MInt getInitialTimeStep(const MBool restartFile, const MPI_Comm comm)
Return the initial global time step.
MInt m_postDataSolverId
Definition: application.h:96
void storeTimingsAndSolverInformation(const MBool finalTimeStep)
Store timings for all solvers and domain decomposition information on all domains.
MInt m_noSolvers
The number of solvers.
Definition: application.h:82
std::vector< std::pair< MString, MInt > > m_domainInfo
Definition: application.h:119
MBool m_writeSolverTimings
Solver/coupler timings for performance evaluations.
Definition: application.h:106
void initTimings()
Initialize the collection of solver/coupler timings for performance evaluations.
const MInt m_maxNoSolverTimings
Definition: application.h:114
MBool m_postProcessing
Definition: application.h:94
void createSolver(CartesianGrid< nDim > *grid, const MInt solverId, Geometry< nDim > *geometry, MBool *propertiesGroup, MBool &isActive)
This function handels the creation of new solvers.
PostProcessingInterface * createPostProcessing(MInt)
This function handels the creation of the Postprocessing classes.
Application()
Gets initial data from the property file and creates the solvers and methods.
static MInt propertyLength(const MString &name, MInt solverId=m_noSolvers)
Returns the number of elements of a property.
Definition: context.cpp:538
static MBool propertyExists(const MString &name, MInt solver=m_noSolvers)
This function checks if a property exists in general.
Definition: context.cpp:494
void createDlbTimers(const MInt noTimers, const MBool ignore=false)
Create the given number of DLB timers.
Definition: dlbtimer.h:235
void enableAllDlbTimers(const MBool *const wasEnabled=nullptr)
Enable all DLB timers (or those given by the array wasEnabled)
Definition: dlbtimer.h:265
void disableAllDlbTimers(MBool *const wasEnabled=nullptr)
Disable all (enabled) DLB timers.
Definition: dlbtimer.h:300
Base recipe provides public interface to Application.
virtual void postTimeStep() final
: Calls each solvers postTimeStep - might be empty
virtual void postCouple() final
: Calls each couplers postCouple - might be empty
MBool callAdaptation() const
virtual void preCouple() final
: Calls each couplers preCouple - might be empty
virtual MBool updateCallOrder()
virtual void preTimeStep() final
: Calls each solvers preTimeStep - might be empty
MInt a_step() const
virtual void timeStep()
: Single solver time step function. Calls solutionStep() of the specific solver
2D structured solver class
3D structured solver class
MPI_Comm mpiComm() const
Definition: geometry.h:45
Definition: lpt.h:82
This class represents all LB models.
Definition: lbsolverdxqy.h:29
static std::unique_ptr< LsCartesianSolver< nDim > > create(MInt solverId_, const MBool *propertiesGroups, GridProxy &gridProxy_, Geometry< nDim > &geometry_, const MPI_Comm comm)
Factory method for LsCartesianSolver.
Definition: lsfvmb.h:24
Definition: postdata.h:23
void ppSolution()
void init()
void setStep(const MInt step)
void preSolve()
void postSolve()
void inSolve(MBool finalTimeStep)
This class is a ScratchSpace.
Definition: scratch.h:758
Structured grid class.
MPI_Comm mpiComm() const
MBool isActive() const
Return whether the solver is active on the current domain.
static std::unique_ptr< Solver > create(const MInt solverId, maia::grid::Proxy< nDim > &gridProxy, Geometry< nDim > &geometry, const MPI_Comm comm)
MInt string2enum(MString theString)
This global function translates strings in their corresponding enum values (integer values)....
Definition: enums.cpp:20
@ COUPLER_LB_DG_APE
Definition: enums.h:407
@ COUPLER_FV_ZONAL_STG
Definition: enums.h:396
@ COUPLER_FV_ZONAL_RTV
Definition: enums.h:395
@ COUPLER_FV_MULTILEVEL_INTERPOLATION
Definition: enums.h:394
@ COUPLER_LS_FV_COMBUSTION
Definition: enums.h:392
@ COUPLER_LB_FV_EE_MULTIPHASE
Definition: enums.h:405
@ COUPLER_LS_FV
Definition: enums.h:391
@ COUPLER_LS_LB_SURFACE
Definition: enums.h:401
@ COUPLER_CARTESIAN_INTERPOLATION
Definition: enums.h:397
@ COUPLER_LB_RB
Definition: enums.h:408
@ COUPLER_LB_LB
Definition: enums.h:406
@ COUPLER_FV_DG_APE
Definition: enums.h:398
@ COUPLER_FV_PARTICLE
Definition: enums.h:399
@ COUPLER_FV_MB_ZONAL
Definition: enums.h:403
@ COUPLER_LS_FV_MB
Definition: enums.h:390
@ COUPLER_LB_LPT
Definition: enums.h:404
@ COUPLER_FV_MULTILEVEL
Definition: enums.h:393
@ COUPLER_LS_LB
Definition: enums.h:400
@ MAIA_GRID_NONE
Definition: enums.h:48
@ MAIA_GRID_STRUCTURED
Definition: enums.h:48
@ MAIA_GRID_CARTESIAN
Definition: enums.h:48
@ POSTPROCESSING_FVLPT
Definition: enums.h:417
@ POSTPROCESSING_FV
Definition: enums.h:413
@ POSTPROCESSING_LBLPT
Definition: enums.h:418
@ POSTPROCESSING_DG
Definition: enums.h:416
@ POSTPROCESSING_LB
Definition: enums.h:415
@ RECIPE_INTRASTEP
Definition: enums.h:422
@ RECIPE_BASE
Definition: enums.h:422
@ RECIPE_ITERATION
Definition: enums.h:422
@ FV_SYSEQN_NS
Definition: enums.h:332
@ FV_SYSEQN_DETCHEM
Definition: enums.h:332
@ FV_SYSEQN_EEGAS
Definition: enums.h:332
@ FV_SYSEQN_RANS
Definition: enums.h:332
@ RANS_SA_DV
Definition: enums.h:54
@ RANS_SA
Definition: enums.h:53
@ RANS_FS
Definition: enums.h:55
@ RANS_KOMEGA
Definition: enums.h:56
@ MAIA_FINITE_VOLUME
Definition: enums.h:23
@ MAIA_FINITE_CELL
Definition: enums.h:36
@ MAIA_DISCONTINUOUS_GALERKIN
Definition: enums.h:37
@ MAIA_RIGID_BODIES
Definition: enums.h:44
@ MAIA_FV_APE
Definition: enums.h:24
@ MAIA_FV_MB
Definition: enums.h:27
@ MAIA_LATTICE_BOLTZMANN
Definition: enums.h:35
@ MAIA_STRUCTURED
Definition: enums.h:40
@ MAIA_LEVELSET_SOLVER
Definition: enums.h:31
@ MAIA_ACOUSTIC_ANALOGY
Definition: enums.h:43
@ MAIA_POST_DATA
Definition: enums.h:45
@ MAIA_PARTICLE
Definition: enums.h:42
@ DG_SYSEQN_ACOUSTICPERTURB
Definition: enums.h:330
@ DG_SYSEQN_LINEARSCALARADV
Definition: enums.h:330
@ PROPERTIESGROUPS_COUNT
Definition: enums.h:282
@ COMBUSTION
Definition: enums.h:276
@ LS_SOLVER
Definition: enums.h:280
@ LEVELSETMB
Definition: enums.h:275
@ LEVELSET
Definition: enums.h:274
@ DG
Definition: enums.h:279
@ LS_RANS
Definition: enums.h:277
@ LEVELSET_LB
Definition: enums.h:281
@ LB
Definition: enums.h:278
void mTerm(const MInt errorCode, const MString &location, const MString &message)
Definition: functions.cpp:29
void writeMemoryStatistics(const MPI_Comm comm, const MInt noDomains, const MInt domainId, const MString at, const MString comment)
Write memory statistics.
Definition: functions.cpp:218
const MString const MString & message
Definition: functions.h:37
void createDir(const std::string &dir)
Definition: functions.h:462
MFloat wallTime()
Definition: functions.h:80
MInt globalTimeStep
MInt globalNoDomains()
Return global number of domains.
MInt globalDomainId()
Return global domain id.
MInt g_timeSteps
MInt g_restartTimeStep
MBool g_splitMpiComm
MBool g_multiSolverGrid
InfoOutFile m_log
MBool g_dynamicLoadBalancing
std::ostream cerr0
int32_t MInt
Definition: maiatypes.h:62
uint32_t MUint
Definition: maiatypes.h:63
std::basic_string< char > MString
Definition: maiatypes.h:55
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
int MPI_Bcast(void *buffer, int count, MPI_Datatype datatype, int root, MPI_Comm comm, const MString &name, const MString &varname)
same as MPI_Bcast
void const MInt const MInt const MInt const MInt maxNoCells
Definition: collector.h:240
DlbTimerController g_dlbTimerController
Namespace for auxiliary functions/classes.
PARALLELIO_DEFAULT_BACKEND ParallelIo
Definition: parallelio.h:292
void logDuration_(const MFloat timeStart, const MString module, const MString comment, const MPI_Comm comm, const MInt domainId, const MInt noDomains)
Output the min/max/average duration of a code section over the ranks in a communicator Note: only use...
Definition: timer.cpp:171