Peano
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 
51 using namespace benchmarks::exahype2::ccz4;
52 
53 tarch::logging::Log _log("::");
54 
55 
56 tarch::timing::Measurement timePerMeshSweepMeasurement;
57 tarch::timing::Measurement gridConstructionMeasurement;
58 tarch::timing::Measurement timeStepMeasurement;
59 tarch::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 
235 void 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 
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;
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)
Definition: ccz4-main.cpp:422
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()
Definition: ccz4-main.cpp:235
tarch::logging::Log _log("::")