Peano
Loading...
Searching...
No Matches
ccz4-main.cpp
Go to the documentation of this file.
1// **********************************************************************************************
2// *** !!!WARNING!!! ***
3// *** WARNING: AUTO GENERATED FILE! DO NOT MODIFY BY HAND! YOUR CHANGES WILL BE OVERWRITTEN! ***
4// *** !!!WARNING!!! ***
5// *** Generated by Peano's Python API: www.peano-framework.org ***
6// **********************************************************************************************
7
8#include <iomanip>
9
10#include "ccz4-main.h"
11
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"
18
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"
26
27#include "repositories/DataRepository.h"
28#include "repositories/SolverRepository.h"
29#include "repositories/StepRepository.h"
30
31
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"
44
46#if defined(USE_ADDITIONAL_MESH_TRAVERSAL)
47 #include "observers/AdditionalMeshTraversal.h"
48#endif
50
51using namespace benchmarks::exahype2::ccz4;
52
53tarch::logging::Log _log("::");
54
55
56tarch::timing::Measurement timePerMeshSweepMeasurement;
57tarch::timing::Measurement gridConstructionMeasurement;
58tarch::timing::Measurement timeStepMeasurement;
59tarch::timing::Measurement plotMeasurement;
60
61
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()
81 );
82 static int globalNumberOfTrees = 0;
83 bool continueToSolve = true;
84
85 if (tarch::hasNonCriticalAssertionBeenViolated() and not haveReceivedNoncriticialAssertion) {
86 peano4::parallel::Node::getInstance().setNextProgramStep(
87 repositories::StepRepository::toProgramStep(repositories::StepRepository::Steps::PlotSolution)
88 );
89 haveReceivedNoncriticialAssertion = true;
90 logError(
91 "selectNextAlgorithmicStep()", "non-critical assertion has been triggered in code. Dump final state and terminate"
92 );
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");
98 gridBalanced = true;
99 } else {
100 logInfo(
101 "selectNextAlgorithmicStep()", "wait for load balancing to become stable: " << repositories::loadBalancer
102 );
103 }
104
105 peano4::parallel::Node::getInstance().setNextProgramStep(repositories::StepRepository::toProgramStep(
106 repositories::StepRepository::Steps::CreateGridAndConvergeLoadBalancing
107 ));
108 } else if (gridBalanced and not gridInitialised) {
109 peano4::parallel::Node::getInstance().setNextProgramStep(
110 repositories::StepRepository::toProgramStep(repositories::StepRepository::Steps::InitGrid)
111 );
112
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();
117 logDebug(
118 "selectNextAlgorithmicStep()", "mesh has refined, so reset minH=" << minH << " and postpone further refinement"
119 );
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();
125 }
126 else if (
127 peano4::parallel::SpacetreeSet::getInstance().getGridStatistics().getStationarySweeps()>5
128 and
129 // ensure that a proper creation has been ran before, so the mesh had the opportunity
130 // to refine further if it has not done yet
131 repositories::StepRepository::toStepEnum( peano4::parallel::Node::getInstance().getCurrentProgramStep() ) == repositories::StepRepository::Steps::CreateGrid
132 ) {
133 logInfo(
134 "selectNextAlgorithmicStep()", "grid has been stationary for quite some time. Terminate grid construction"
135 );
136 addGridSweepWithoutGridRefinementNext = false;
137 gridConstructed = true;
138 } else {
139 logInfo(
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()
143 );
144 addGridSweepWithoutGridRefinementNext = false;
145 globalNumberOfTrees = repositories::loadBalancer.getGlobalNumberOfTrees();
146 }
147
148 // Actual grid traversal choice
149 if (addGridSweepWithoutGridRefinementNext) {
150 peano4::parallel::Node::getInstance().setNextProgramStep(repositories::StepRepository::toProgramStep(
151 repositories::StepRepository::Steps::CreateGridButPostponeRefinement
152 ));
153 } else {
154 peano4::parallel::Node::getInstance().setNextProgramStep(
155 repositories::StepRepository::toProgramStep(repositories::StepRepository::Steps::CreateGrid)
156 );
157 }
158
159 continueToSolve = true;
160 } else {
162 #if defined(USE_ADDITIONAL_MESH_TRAVERSAL)
163 if (
164 repositories::isLastGridSweepOfTimeStep()
165 and
166 repositories::StepRepository::toStepEnum( peano4::parallel::Node::getInstance().getCurrentProgramStep() ) != repositories::StepRepository::Steps::AdditionalMeshTraversal
167 ) {
168 peano4::parallel::Node::getInstance().setNextProgramStep(
169 repositories::StepRepository::toProgramStep( repositories::StepRepository::Steps::AdditionalMeshTraversal )
170 );
171 continueToSolve = true;
172 } else
173 #endif
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;
178 }
179 if (repositories::getMaxTimeStamp() >= nextMaxPlotTimeStamp) {
180 nextMaxPlotTimeStamp += TimeInBetweenPlots;
181 }
182
183 if (nextMinPlotTimeStamp < repositories::getMinTimeStamp()) {
184 logWarning(
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)
189 );
190 nextMinPlotTimeStamp = repositories::getMinTimeStamp() + TimeInBetweenPlots;
191 } else if (nextMaxPlotTimeStamp < repositories::getMaxTimeStamp()) {
192 logWarning(
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)
197 );
198 nextMaxPlotTimeStamp = repositories::getMaxTimeStamp() + TimeInBetweenPlots;
199 }
200
201 nextMaxPlotTimeStamp = std::max(nextMaxPlotTimeStamp, nextMinPlotTimeStamp);
202
203 peano4::parallel::Node::getInstance().setNextProgramStep(
204 repositories::StepRepository::toProgramStep(repositories::StepRepository::Steps::PlotSolution)
205 );
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)
211 );
212 continueToSolve = true;
213 haveJustWrittenSnapshot = false;
214 } else {
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)
218 );
219 continueToSolve = true; // don't want to terminate immediately
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; // don't want to terminate immediately but to wait for incomplete time steps to complete
225 } else {
226 continueToSolve = false;
227 }
228 }
229 }
230
231 return continueToSolve;
232}
233
234
235void step() {
236 int stepIdentifier = peano4::parallel::Node::getInstance().getCurrentProgramStep();
237 auto stepName = repositories::StepRepository::toStepEnum(stepIdentifier);
238
239 static tarch::logging::Log _log("");
240#if PEANO_DEBUG > 0
241#else
242 if (tarch::mpi::Rank::getInstance().isGlobalMaster())
243#endif
244 logInfo("step()", "run " << repositories::StepRepository::toString(stepName));
245
246 static tarch::timing::Watch watch("::", "step()", false);
247
248 static int creepingNumberOfLocalCells = 0;
249
250 switch (stepName) {
251 case repositories::StepRepository::Steps::CreateGridButPostponeRefinement: {
252 tarch::logging::LogFilter::getInstance().switchProgramPhase("create-grid-but-postpone-refinement");
253
254 repositories::startGridConstructionStep();
255
256 observers::CreateGridButPostponeRefinement observer;
257 watch.start();
258 peano4::parallel::SpacetreeSet::getInstance().traverse(observer);
259 watch.stop();
260 gridConstructionMeasurement.setValue(watch.getCalendarTime());
261
262 repositories::finishGridConstructionStep();
263 } break;
264 case repositories::StepRepository::Steps::CreateGrid: {
265 tarch::logging::LogFilter::getInstance().switchProgramPhase("create-grid");
266
267 repositories::startGridConstructionStep();
268
269 observers::CreateGrid observer;
270 watch.start();
271 peano4::parallel::SpacetreeSet::getInstance().traverse(observer);
272 watch.stop();
273 gridConstructionMeasurement.setValue(watch.getCalendarTime());
274
275 repositories::finishGridConstructionStep();
276
277 // We always overestimate so give the convergence the opportunity to catch up. The constant
278 // here is a magic one.
279 creepingNumberOfLocalCells = ::toolbox::loadbalancing::getWeightOfHeaviestLocalSpacetree()
280 + tarch::multicore::Core::getInstance().getNumberOfThreads() * 3;
281 } break;
282 case repositories::StepRepository::Steps::CreateGridAndConvergeLoadBalancing: {
283 if (creepingNumberOfLocalCells < ::toolbox::loadbalancing::getWeightOfHeaviestLocalSpacetree() - 1) {
284 logInfo(
285 "step()",
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"
287 );
288 creepingNumberOfLocalCells = ::toolbox::loadbalancing::getWeightOfHeaviestLocalSpacetree()
289 + tarch::multicore::Core::getInstance().getNumberOfThreads() * 3;
290 }
291
292 tarch::logging::LogFilter::getInstance().switchProgramPhase("create-grid-and-converge-load-balancing");
293
294 // The smaller here corresponds to the -1 below
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);
298 }
299 if (
300 ::toolbox::loadbalancing::getWeightOfHeaviestLocalSpacetree() >= creepingNumberOfLocalCells
301 and
302 repositories::loadBalancer.isEnabled(false)
303 ) {
304 logInfo(
305 "step()",
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"
308 );
309 repositories::loadBalancer.enable(false);
310 }
311
312 repositories::startGridConstructionStep();
313
314 observers::CreateGridButPostponeRefinement observer;
315 watch.start();
316 peano4::parallel::SpacetreeSet::getInstance().traverse(observer);
317 watch.stop();
318 gridConstructionMeasurement.setValue(watch.getCalendarTime());
319
320 repositories::finishGridConstructionStep();
321
322 if (
323 ::toolbox::loadbalancing::getWeightOfHeaviestLocalSpacetree() <= creepingNumberOfLocalCells
324 and
325 not repositories::loadBalancer.hasSplitRecently()
326 and
327 repositories::loadBalancer.isEnabled(false)
328 ) {
329 logInfo(
330 "step()",
331 "have to decrement local cell counter "
332 << creepingNumberOfLocalCells << " as maximum weight is "
333 << ::toolbox::loadbalancing::getWeightOfHeaviestLocalSpacetree()
334 );
335 creepingNumberOfLocalCells = (creepingNumberOfLocalCells
336 + ::toolbox::loadbalancing::getWeightOfHeaviestLocalSpacetree())
337 / 2;
338 }
339 } break;
340 case repositories::StepRepository::Steps::InitGrid: {
341 tarch::logging::LogFilter::getInstance().switchProgramPhase("init-grid");
342 repositories::loadBalancer.enable(false);
343
344 repositories::startGridInitialisationStep();
345
346 observers::InitGrid observer;
347 observers::InitGrid::prepareTraversal();
348 watch.start();
349 peano4::parallel::SpacetreeSet::getInstance().traverse(observer);
350 watch.stop();
351 observers::InitGrid::unprepareTraversal();
352 gridConstructionMeasurement.setValue(watch.getCalendarTime());
353
354 repositories::finishGridInitialisationStep();
355 } break;
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();
362
363 repositories::startPlottingStep(minTimeStamp, maxTimeStamp, minTimeStepSize, maxTimeStepSize);
364
365 observers::PlotSolution observer;
366 observers::PlotSolution::prepareTraversal();
367 watch.start();
368 peano4::parallel::SpacetreeSet::getInstance().traverse(observer);
369 watch.stop();
370 observers::PlotSolution::unprepareTraversal();
371 plotMeasurement.setValue(watch.getCalendarTime());
372
373 repositories::finishPlottingStep();
374 } break;
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);
380 }
381
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();
388
389 repositories::startTimeStep(minTimeStamp, maxTimeStamp, minTimeStepSize, maxTimeStepSize);
390
391 observers::TimeStep observer;
392 observers::TimeStep::prepareTraversal();
393 watch.start();
394 peano4::parallel::SpacetreeSet::getInstance().traverse(observer);
395 watch.stop();
396 observers::TimeStep::unprepareTraversal();
397 timeStepMeasurement.setValue(watch.getCalendarTime());
398
399 repositories::finishTimeStep();
400 } break;
402 #if defined(USE_ADDITIONAL_MESH_TRAVERSAL)
403 case repositories::StepRepository::Steps::AdditionalMeshTraversal:
404 {
405 tarch::logging::LogFilter::getInstance().switchProgramPhase( "additional-MeshTraversal" );
406
407 repositories::suspendSolversForOneGridSweep();
408 observers::AdditionalMeshTraversal observer;
409 observers::AdditionalMeshTraversal::prepareTraversal();
410 peano4::parallel::SpacetreeSet::getInstance().traverse(observer);
411 observers::AdditionalMeshTraversal::unprepareTraversal();
412 }
413 break;
414 #endif
416 case repositories::StepRepository::Steps::Undef:
417 assertion(false);
418 break;
419 }
420}
421
422int 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;
427
428 static tarch::timing::Watch watch("::", "main()", false);
429
430 peano4::initParallelEnvironment(&argc, &argv);
431
432 // Do this early, so people can use logInfo properly.
433 repositories::initLogFilters();
434
435 tarch::initNonCriticalAssertionEnvironment();
436 peano4::fillLookupTables();
437
438 peano4::initSingletons(DomainOffset, DomainSize, PeriodicBC);
439
440 repositories::initSharedMemoryAndGPUEnvironment();
441
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;
445 }
446
447 repositories::DataRepository::initDatatypes();
448
449 #if PEANO_DEBUG >= 2
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());
455 unitTests->run();
456 if (unitTests->getNumberOfErrors() != 0) {
457 logError("main()", "unit tests failed. Quit.");
458 tarch::mpi::Rank::abort(ExitCodeUnitTestsFailed);
459 }
460 delete unitTests;
461#endif
462
463 repositories::startSimulation();
464
465 tarch::logging::Statistics::getInstance().clear();
466
467#if defined(WITH_OPENMP)
468#pragma omp parallel
469 {
470#pragma omp master
471 {
472#endif
473
474 const bool isGlobalMaster = tarch::mpi::Rank::getInstance().isGlobalMaster();
475 const bool isPeanoComputeNode = not tarch::mpi::Rank::getInstance().isGlobalMaster();
476
477 if (isGlobalMaster) {
478 while (selectNextAlgorithmicStep()) {
479 watch.start();
480 step();
481 watch.stop();
482
483 timePerMeshSweepMeasurement.setValue(watch.getCalendarTime());
484 logInfo(
485 "main()",
486 "time per mesh sweep (current/average): " << std::fixed << std::setprecision(2) << watch.getCalendarTime() <<
487 "s / " << timePerMeshSweepMeasurement.getValue() << "s"
488 );
489 }
490
491 logInfo("main()", "terminated successfully");
492 logInfo(
493 "main()",
494 "initial grid construction: " << gridConstructionMeasurement.getAccumulatedValue() <<
495 "s\t" << gridConstructionMeasurement.toString()
496 );
497 logInfo(
498 "main()",
499 "plotting: " << plotMeasurement.getAccumulatedValue() <<
500 "s\t" << plotMeasurement.toString()
501 );
502 logInfo(
503 "main()",
504 "time stepping: " << timeStepMeasurement.getAccumulatedValue() <<
505 "s\t" << timeStepMeasurement.toString()
506 );
507 logInfo(
508 "main()",
509 "average time per mesh sweep: " << timePerMeshSweepMeasurement.getValue() <<
510 "s\t" << timePerMeshSweepMeasurement.toString()
511 );
512 } else if (isPeanoComputeNode) {
513 while (peano4::parallel::Node::getInstance().continueToRun()) {
514 step();
515 }
516 }
517#if defined(WITH_OPENMP)
518 }
519 }
520#endif
521
522 tarch::logging::Statistics::getInstance().writeToCSV();
523
524 repositories::finishSimulation();
525
526 peano4::shutdownSingletons();
527 repositories::DataRepository::shutdownDatatypes();
528 tarch::shutdownNonCriticalAssertionEnvironment();
529 peano4::shutdownParallelEnvironment();
530
531 return ExitCodeSuccess;
532}
tarch::timing::Measurement gridConstructionMeasurement
Definition ccz4-main.cpp:57
int main(int argc, char **argv)
tarch::timing::Measurement timePerMeshSweepMeasurement
Definition ccz4-main.cpp:56
tarch::timing::Measurement timeStepMeasurement
Definition ccz4-main.cpp:58
bool selectNextAlgorithmicStep()
Decide which step to run next.
Definition ccz4-main.cpp:70
tarch::timing::Measurement plotMeasurement
Definition ccz4-main.cpp:59
void step()
tarch::logging::Log _log("::")