10 #include "ccz4-main.h"
12 #include "exahype2/UnitTests.h"
13 #include "exahype2/UserInterface.h"
14 #include "peano4/peano4.h"
15 #include "peano4/UnitTests.h"
16 #include "peano4/grid/Spacetree.h"
17 #include "peano4/parallel/SpacetreeSet.h"
19 #include "Constants.h"
20 #include "observers/CreateGrid.h"
21 #include "observers/CreateGridAndConvergeLoadBalancing.h"
22 #include "observers/CreateGridButPostponeRefinement.h"
23 #include "observers/InitGrid.h"
24 #include "observers/PlotSolution.h"
25 #include "observers/TimeStep.h"
27 #include "repositories/DataRepository.h"
28 #include "repositories/SolverRepository.h"
29 #include "repositories/StepRepository.h"
32 #include "tarch/UnitTests.h"
33 #include "tarch/logging/Log.h"
34 #include "tarch/logging/LogFilter.h"
35 #include "tarch/logging/Statistics.h"
36 #include "tarch/multicore/Core.h"
37 #include "tarch/multicore/multicore.h"
38 #include "tarch/NonCriticalAssertions.h"
39 #include "tarch/tests/TreeTestCaseCollection.h"
40 #include "tarch/timing/Measurement.h"
41 #include "tarch/timing/Watch.h"
42 #include "toolbox/blockstructured/UnitTests.h"
43 #include "toolbox/loadbalancing/loadbalancing.h"
46 #if defined(USE_ADDITIONAL_MESH_TRAVERSAL)
47 #include "observers/AdditionalMeshTraversal.h"
53 tarch::logging::Log
_log(
"::");
71 static bool gridConstructed =
false;
72 static bool gridInitialised =
false;
73 static bool gridBalanced =
false;
74 static double nextMaxPlotTimeStamp = FirstPlotTimeStamp;
75 static double nextMinPlotTimeStamp = FirstPlotTimeStamp;
76 static bool haveJustWrittenSnapshot =
false;
77 static bool haveReceivedNoncriticialAssertion =
false;
78 static bool addGridSweepWithoutGridRefinementNext =
false;
79 static tarch::la::Vector<DIMENSIONS, double> minH = tarch::la::Vector<DIMENSIONS, double>(
80 std::numeric_limits<double>::max()
82 static int globalNumberOfTrees = 0;
83 bool continueToSolve =
true;
85 if (tarch::hasNonCriticalAssertionBeenViolated() and not haveReceivedNoncriticialAssertion) {
86 peano4::parallel::Node::getInstance().setNextProgramStep(
87 repositories::StepRepository::toProgramStep(repositories::StepRepository::Steps::PlotSolution)
89 haveReceivedNoncriticialAssertion =
true;
91 "selectNextAlgorithmicStep()",
"non-critical assertion has been triggered in code. Dump final state and terminate"
93 }
else if (tarch::hasNonCriticalAssertionBeenViolated()) {
94 continueToSolve =
false;
95 }
else if (gridConstructed and not gridBalanced) {
96 if (not repositories::loadBalancer.isEnabled(
true) and not repositories::loadBalancer.hasSplitRecently()) {
97 logInfo(
"selectNextAlgorithmicStep()",
"all ranks have switched off their load balancing");
101 "selectNextAlgorithmicStep()",
"wait for load balancing to become stable: " << repositories::loadBalancer
105 peano4::parallel::Node::getInstance().setNextProgramStep(repositories::StepRepository::toProgramStep(
106 repositories::StepRepository::Steps::CreateGridAndConvergeLoadBalancing
108 }
else if (gridBalanced and not gridInitialised) {
109 peano4::parallel::Node::getInstance().setNextProgramStep(
110 repositories::StepRepository::toProgramStep(repositories::StepRepository::Steps::InitGrid)
113 gridInitialised =
true;
114 }
else if (not gridConstructed) {
115 if (tarch::la::max(peano4::parallel::SpacetreeSet::getInstance().getGridStatistics().getMinH()) < tarch::la::max(minH)) {
116 minH = peano4::parallel::SpacetreeSet::getInstance().getGridStatistics().getMinH();
118 "selectNextAlgorithmicStep()",
"mesh has refined, so reset minH=" << minH <<
" and postpone further refinement"
120 addGridSweepWithoutGridRefinementNext =
true;
121 }
else if (repositories::loadBalancer.getGlobalNumberOfTrees() > globalNumberOfTrees) {
122 logInfo(
"selectNextAlgorithmicStep()",
"mesh has rebalanced recently, so postpone further refinement)");
123 addGridSweepWithoutGridRefinementNext =
true;
124 globalNumberOfTrees = repositories::loadBalancer.getGlobalNumberOfTrees();
127 peano4::parallel::SpacetreeSet::getInstance().getGridStatistics().getStationarySweeps()>5
131 repositories::StepRepository::toStepEnum( peano4::parallel::Node::getInstance().getCurrentProgramStep() ) == repositories::StepRepository::Steps::CreateGrid
134 "selectNextAlgorithmicStep()",
"grid has been stationary for quite some time. Terminate grid construction"
136 addGridSweepWithoutGridRefinementNext =
false;
137 gridConstructed =
true;
140 "selectNextAlgorithmicStep()",
141 "mesh rebalancing seems to be stationary, so study whether to refine mesh further in next sweep: "
142 << peano4::parallel::SpacetreeSet::getInstance().getGridStatistics().toString()
144 addGridSweepWithoutGridRefinementNext =
false;
145 globalNumberOfTrees = repositories::loadBalancer.getGlobalNumberOfTrees();
149 if (addGridSweepWithoutGridRefinementNext) {
150 peano4::parallel::Node::getInstance().setNextProgramStep(repositories::StepRepository::toProgramStep(
151 repositories::StepRepository::Steps::CreateGridButPostponeRefinement
154 peano4::parallel::Node::getInstance().setNextProgramStep(
155 repositories::StepRepository::toProgramStep(repositories::StepRepository::Steps::CreateGrid)
159 continueToSolve =
true;
162 #if defined(USE_ADDITIONAL_MESH_TRAVERSAL)
164 repositories::isLastGridSweepOfTimeStep()
166 repositories::StepRepository::toStepEnum( peano4::parallel::Node::getInstance().getCurrentProgramStep() ) != repositories::StepRepository::Steps::AdditionalMeshTraversal
168 peano4::parallel::Node::getInstance().setNextProgramStep(
169 repositories::StepRepository::toProgramStep( repositories::StepRepository::Steps::AdditionalMeshTraversal )
171 continueToSolve =
true;
175 if (TimeInBetweenPlots > 0.0 and repositories::getMinTimeStamp() < MinTerminalTime and repositories::getMaxTimeStamp() < MaxTerminalTime and (repositories::getMinTimeStamp() >= nextMinPlotTimeStamp or repositories::getMaxTimeStamp() >= nextMaxPlotTimeStamp) and repositories::mayPlot()) {
176 if (repositories::getMinTimeStamp() >= nextMinPlotTimeStamp) {
177 nextMinPlotTimeStamp += TimeInBetweenPlots;
179 if (repositories::getMaxTimeStamp() >= nextMaxPlotTimeStamp) {
180 nextMaxPlotTimeStamp += TimeInBetweenPlots;
183 if (nextMinPlotTimeStamp < repositories::getMinTimeStamp()) {
185 "selectNextAlgorithmicStep()",
186 "code is asked to plot every dt="
187 << TimeInBetweenPlots <<
", but this seems to be less than the time step size of the solvers. "
188 <<
"So postpone next plot to t=" << (repositories::getMinTimeStamp() + TimeInBetweenPlots)
190 nextMinPlotTimeStamp = repositories::getMinTimeStamp() + TimeInBetweenPlots;
191 }
else if (nextMaxPlotTimeStamp < repositories::getMaxTimeStamp()) {
193 "selectNextAlgorithmicStep()",
194 "code is asked to plot every dt="
195 << TimeInBetweenPlots <<
", but this seems to be less than the time step size of the solvers. "
196 <<
"So postpone next plot to t=" << (repositories::getMaxTimeStamp() + TimeInBetweenPlots)
198 nextMaxPlotTimeStamp = repositories::getMaxTimeStamp() + TimeInBetweenPlots;
201 nextMaxPlotTimeStamp = std::max(nextMaxPlotTimeStamp, nextMinPlotTimeStamp);
203 peano4::parallel::Node::getInstance().setNextProgramStep(
204 repositories::StepRepository::toProgramStep(repositories::StepRepository::Steps::PlotSolution)
206 haveJustWrittenSnapshot =
true;
207 continueToSolve =
true;
208 }
else if (repositories::getMinTimeStamp() < MinTerminalTime and repositories::getMaxTimeStamp() < MaxTerminalTime) {
209 peano4::parallel::Node::getInstance().setNextProgramStep(
210 repositories::StepRepository::toProgramStep(repositories::StepRepository::Steps::TimeStep)
212 continueToSolve =
true;
213 haveJustWrittenSnapshot =
false;
215 if (not haveJustWrittenSnapshot and TimeInBetweenPlots > 0.0 and repositories::mayPlot()) {
216 peano4::parallel::Node::getInstance().setNextProgramStep(
217 repositories::StepRepository::toProgramStep(repositories::StepRepository::Steps::PlotSolution)
219 continueToSolve =
true;
220 haveJustWrittenSnapshot =
true;
221 nextMinPlotTimeStamp = std::numeric_limits<double>::max();
222 nextMaxPlotTimeStamp = std::numeric_limits<double>::max();
223 }
else if (not haveJustWrittenSnapshot and TimeInBetweenPlots > 0.0 and not repositories::mayPlot()) {
224 continueToSolve =
true;
226 continueToSolve =
false;
231 return continueToSolve;
236 int stepIdentifier = peano4::parallel::Node::getInstance().getCurrentProgramStep();
237 auto stepName = repositories::StepRepository::toStepEnum(stepIdentifier);
239 static tarch::logging::Log
_log(
"");
242 if (tarch::mpi::Rank::getInstance().isGlobalMaster())
244 logInfo(
"step()",
"run " << repositories::StepRepository::toString(stepName));
246 static tarch::timing::Watch watch(
"::",
"step()",
false);
248 static int creepingNumberOfLocalCells = 0;
251 case repositories::StepRepository::Steps::CreateGridButPostponeRefinement: {
252 tarch::logging::LogFilter::getInstance().switchProgramPhase(
"create-grid-but-postpone-refinement");
254 repositories::startGridConstructionStep();
256 observers::CreateGridButPostponeRefinement observer;
258 peano4::parallel::SpacetreeSet::getInstance().traverse(observer);
262 repositories::finishGridConstructionStep();
264 case repositories::StepRepository::Steps::CreateGrid: {
265 tarch::logging::LogFilter::getInstance().switchProgramPhase(
"create-grid");
267 repositories::startGridConstructionStep();
269 observers::CreateGrid observer;
271 peano4::parallel::SpacetreeSet::getInstance().traverse(observer);
275 repositories::finishGridConstructionStep();
279 creepingNumberOfLocalCells = ::toolbox::loadbalancing::getWeightOfHeaviestLocalSpacetree()
280 + tarch::multicore::Core::getInstance().getNumberOfThreads() * 3;
282 case repositories::StepRepository::Steps::CreateGridAndConvergeLoadBalancing: {
283 if (creepingNumberOfLocalCells < ::toolbox::loadbalancing::getWeightOfHeaviestLocalSpacetree() - 1) {
286 "it seems the grid has just refined before we switched to the phase where we make the load balancing converge. Wait for a few iterations more to give load balancing chance to catch up"
288 creepingNumberOfLocalCells = ::toolbox::loadbalancing::getWeightOfHeaviestLocalSpacetree()
289 + tarch::multicore::Core::getInstance().getNumberOfThreads() * 3;
292 tarch::logging::LogFilter::getInstance().switchProgramPhase(
"create-grid-and-converge-load-balancing");
295 if (::toolbox::loadbalancing::getWeightOfHeaviestLocalSpacetree() < 0 and repositories::loadBalancer.isEnabled(
false)) {
296 logInfo(
"step()",
"rank is degenerated so disable load balancing temporarily");
297 repositories::loadBalancer.enable(
false);
300 ::toolbox::loadbalancing::getWeightOfHeaviestLocalSpacetree() >= creepingNumberOfLocalCells
302 repositories::loadBalancer.isEnabled(
false)
306 "grid construction and decomposition on this rank seem to be stable as we have around "
307 << creepingNumberOfLocalCells <<
" local cells in the heaviest tree. Disable load balancing temporarily"
309 repositories::loadBalancer.enable(
false);
312 repositories::startGridConstructionStep();
314 observers::CreateGridButPostponeRefinement observer;
316 peano4::parallel::SpacetreeSet::getInstance().traverse(observer);
320 repositories::finishGridConstructionStep();
323 ::toolbox::loadbalancing::getWeightOfHeaviestLocalSpacetree() <= creepingNumberOfLocalCells
325 not repositories::loadBalancer.hasSplitRecently()
327 repositories::loadBalancer.isEnabled(
false)
331 "have to decrement local cell counter "
332 << creepingNumberOfLocalCells <<
" as maximum weight is "
333 << ::toolbox::loadbalancing::getWeightOfHeaviestLocalSpacetree()
335 creepingNumberOfLocalCells = (creepingNumberOfLocalCells
336 + ::toolbox::loadbalancing::getWeightOfHeaviestLocalSpacetree())
340 case repositories::StepRepository::Steps::InitGrid: {
341 tarch::logging::LogFilter::getInstance().switchProgramPhase(
"init-grid");
342 repositories::loadBalancer.enable(
false);
344 repositories::startGridInitialisationStep();
346 observers::InitGrid observer;
347 observers::InitGrid::prepareTraversal();
349 peano4::parallel::SpacetreeSet::getInstance().traverse(observer);
351 observers::InitGrid::unprepareTraversal();
354 repositories::finishGridInitialisationStep();
356 case repositories::StepRepository::Steps::PlotSolution: {
357 tarch::logging::LogFilter::getInstance().switchProgramPhase(
"plot-solution");
358 const double minTimeStamp = repositories::getMinTimeStamp();
359 const double maxTimeStamp = repositories::getMaxTimeStamp();
360 const double minTimeStepSize = repositories::getMinTimeStepSize();
361 const double maxTimeStepSize = repositories::getMaxTimeStepSize();
363 repositories::startPlottingStep(minTimeStamp, maxTimeStamp, minTimeStepSize, maxTimeStepSize);
365 observers::PlotSolution observer;
366 observers::PlotSolution::prepareTraversal();
368 peano4::parallel::SpacetreeSet::getInstance().traverse(observer);
370 observers::PlotSolution::unprepareTraversal();
373 repositories::finishPlottingStep();
375 case repositories::StepRepository::Steps::TimeStep: {
376 tarch::logging::LogFilter::getInstance().switchProgramPhase(
"time-step");
377 if (repositories::loadBalancer.isEnabled(
false)) {
378 logInfo(
"step()",
"disable load balancing throughout initialisation (to be removed in later releases)");
379 repositories::loadBalancer.enable(
false);
382 const double minTimeStamp = repositories::getMinTimeStamp();
383 const double maxTimeStamp = repositories::getMaxTimeStamp();
384 const double minTimeStepSize = repositories::getMinTimeStepSize();
385 const double maxTimeStepSize = repositories::getMaxTimeStepSize();
386 const double minMeshSize = repositories::getMinMeshSize();
387 const double maxMeshSize = repositories::getMaxMeshSize();
389 repositories::startTimeStep(minTimeStamp, maxTimeStamp, minTimeStepSize, maxTimeStepSize);
391 observers::TimeStep observer;
392 observers::TimeStep::prepareTraversal();
394 peano4::parallel::SpacetreeSet::getInstance().traverse(observer);
396 observers::TimeStep::unprepareTraversal();
399 repositories::finishTimeStep();
402 #if defined(USE_ADDITIONAL_MESH_TRAVERSAL)
403 case repositories::StepRepository::Steps::AdditionalMeshTraversal:
405 tarch::logging::LogFilter::getInstance().switchProgramPhase(
"additional-MeshTraversal" );
407 repositories::suspendSolversForOneGridSweep();
408 observers::AdditionalMeshTraversal observer;
409 observers::AdditionalMeshTraversal::prepareTraversal();
410 peano4::parallel::SpacetreeSet::getInstance().traverse(observer);
411 observers::AdditionalMeshTraversal::unprepareTraversal();
416 case repositories::StepRepository::Steps::Undef:
422 int main(
int argc,
char** argv) {
423 constexpr
int ExitCodeSuccess = 0;
424 constexpr
int ExitCodeUnitTestsFailed = 1;
425 constexpr
int ExitCodeInvalidArguments = 2;
426 constexpr
int ExitCodeInvalidBuild = 3;
428 static tarch::timing::Watch watch(
"::",
"main()",
false);
430 peano4::initParallelEnvironment(&argc, &argv);
433 repositories::initLogFilters();
435 tarch::initNonCriticalAssertionEnvironment();
436 peano4::fillLookupTables();
438 peano4::initSingletons(DomainOffset, DomainSize, PeriodicBC);
440 repositories::initSharedMemoryAndGPUEnvironment();
442 if (tarch::mpi::Rank::getInstance().getNumberOfRanks() > 1 and tarch::multicore::Core::getInstance().getNumberOfThreads() <= 1) {
443 logError(
"main()",
"MPI runs without multithreading are not supported currently.");
444 return ExitCodeInvalidBuild;
447 repositories::DataRepository::initDatatypes();
450 tarch::tests::TreeTestCaseCollection* unitTests =
new tarch::tests::TreeTestCaseCollection();
451 unitTests->addTestCase(peano4::getUnitTests());
452 unitTests->addTestCase(tarch::getUnitTests());
453 unitTests->addTestCase(toolbox::blockstructured::getUnitTests());
454 unitTests->addTestCase(exahype2::getUnitTests());
456 if (unitTests->getNumberOfErrors() != 0) {
457 logError(
"main()",
"unit tests failed. Quit.");
458 tarch::mpi::Rank::abort(ExitCodeUnitTestsFailed);
463 repositories::startSimulation();
465 tarch::logging::Statistics::getInstance().clear();
467 #if defined(WITH_OPENMP)
474 const bool isGlobalMaster = tarch::mpi::Rank::getInstance().isGlobalMaster();
475 const bool isPeanoComputeNode = not tarch::mpi::Rank::getInstance().isGlobalMaster();
477 if (isGlobalMaster) {
486 "time per mesh sweep (current/average): " << std::fixed << std::setprecision(2) << watch.getCalendarTime() <<
491 logInfo(
"main()",
"terminated successfully");
512 }
else if (isPeanoComputeNode) {
513 while (peano4::parallel::Node::getInstance().continueToRun()) {
517 #if defined(WITH_OPENMP)
522 tarch::logging::Statistics::getInstance().writeToCSV();
524 repositories::finishSimulation();
526 peano4::shutdownSingletons();
527 repositories::DataRepository::shutdownDatatypes();
528 tarch::shutdownNonCriticalAssertionEnvironment();
529 peano4::shutdownParallelEnvironment();
531 return ExitCodeSuccess;
tarch::timing::Measurement gridConstructionMeasurement
int main(int argc, char **argv)
tarch::timing::Measurement timePerMeshSweepMeasurement
tarch::timing::Measurement timeStepMeasurement
bool selectNextAlgorithmicStep()
Decide which step to run next.
tarch::timing::Measurement plotMeasurement
tarch::logging::Log _log("::")