Peano
Loading...
Searching...
No Matches
KernelBenchmarks-main.cpp
Go to the documentation of this file.
1// This file is part of the ExaHyPE2 project. For conditions of distribution and
2// use, please see the copyright notice at www.peano-framework.org
3#include "KernelBenchmarks-main.h"
4
5#include "AbstractFVSolver.h"
6#include "Constants.h"
7#include "DataRepository.h"
8#include "FVSolver.h"
9#include "celldata/FVSolverQ.h"
10#include "celldata/FVSolverQReconstructed.h"
11#include "exahype2/CellData.h"
12#include "exahype2/EnclaveBookkeeping.h"
13#include "exahype2/fv/BoundaryConditions.h"
14#include "exahype2/fv/PatchUtils.h"
15#include "facedata/FVSolverQNew.h"
16#include "kernels/FVSolver/ReconstructPatch.h"
17#include "peano4/datamanagement/CellMarker.h"
18#include "peano4/datamanagement/FaceEnumerator.h"
19#include "peano4/peano4.h"
20#include "peano4/utils/Globals.h"
21#include "peano4/utils/Loop.h"
22#include "tarch/logging/Log.h"
23#include "tarch/plotter/griddata/blockstructured/PeanoTextPatchFileWriter.h"
24#include "tarch/timing/Measurement.h"
25#include "tarch/timing/Watch.h"
26#include "tasks/FVSolverEnclaveTask.h"
27#include "toolbox/blockstructured/Projection.h"
28
30
31namespace {
32 tarch::logging::Log _log("");
33 tarch::timing::Measurement timeStepMeasurement;
34 double printNextTimeStep = 0.0;
35 bool haveReceivedNonCriticalAssertion = false;
36
37 std::vector<peano4::datamanagement::CellMarker> _cells;
38 const tarch::la::Vector<DIMENSIONS, double> CellSize = DomainSize / static_cast<double>(GridLength);
39} // namespace
40
41void reportRuntime(const tarch::timing::Measurement& measurement) {
42 const std::string context = "reportRuntime()";
43 constexpr int LabelWidth = 25; // Set a fixed width for all labels
44
45 if (measurement.getNumberOfMeasurements() == 0) {
46 logInfo(context, "Timing Measurement Report: No data recorded.");
47 return;
48 }
49
50 logInfo(context, "---------- Timing Measurement Report ----------");
51 double avg = measurement.getValue();
52 double std_dev = measurement.getStandardDeviation();
53 double min_val = measurement.min();
54 double max_val = measurement.max();
55 int min_idx = measurement.getMinMeasurement();
56 int max_idx = measurement.getMaxMeasurement();
57 double min_dev_percent = (avg == 0) ? 0.0 : (min_val / avg - 1.0) * 100.0;
58 double max_dev_percent = (avg == 0) ? 0.0 : (max_val / avg - 1.0) * 100.0;
59
60 std::stringstream msg;
61
62 msg.str("");
63 msg << std::left << std::setw(LabelWidth) << "Average Value:" << std::fixed << std::setprecision(8) << avg << "s";
64 logInfo(context, msg.str());
65
66 msg.str("");
67 msg << std::left << std::setw(LabelWidth) << "Average Cell Updates:" << std::fixed << std::setprecision(0)
68 << _cells.size() / avg;
69 logInfo(context, msg.str());
70
71 msg.str("");
72 msg << std::left << std::setw(LabelWidth) << "Standard Deviation:" << std::scientific << std::setprecision(8)
73 << std_dev;
74 logInfo(context, msg.str());
75
76 msg.str("");
77 msg << std::left << std::setw(LabelWidth) << "# Measurements:" << measurement.getNumberOfMeasurements();
78 logInfo(context, msg.str());
79
80 msg.str("");
81 msg
82 << std::left << std::setw(LabelWidth) << "Min Value:" << std::fixed << std::setprecision(8) << min_val << "s (at #"
83 << min_idx << ") "
84 << "[" << std::fixed << std::setprecision(2) << min_dev_percent << "%]";
85 logInfo(context, msg.str());
86
87 msg.str("");
88 msg
89 << std::left << std::setw(LabelWidth) << "Max Value:" << std::fixed << std::setprecision(8) << max_val << "s (at #"
90 << max_idx << ") " << std::showpos // Show the '+' sign
91 << "[" << std::fixed << std::setprecision(2) << max_dev_percent << "%]";
92 logInfo(context, msg.str());
93
94 msg.str("");
95 msg << std::left << std::setw(LabelWidth) << "Most Recent Value:" << std::fixed << std::setprecision(8)
96 << measurement.getMostRecentValue() << "s";
97 logInfo(context, msg.str());
98
99 msg.str("");
100 msg << std::left << std::setw(LabelWidth) << "Accumulated Time:" << std::fixed << std::setprecision(8)
101 << measurement.getAccumulatedValue() << "s";
102 logInfo(context, msg.str());
103
104 logInfo(context, "-----------------------------------------------");
105}
106
107void plotGrid() {
108 repositories::startPlottingStep();
109 static int counter = -1;
110 counter++;
111
112 std::ostringstream snapshotFileName;
113 snapshotFileName << "solutions/solution-FVSolver-" << counter;
114
115 auto writer = tarch::plotter::griddata::blockstructured::PeanoTextPatchFileWriter(
116 DIMENSIONS,
117 snapshotFileName.str(),
118 "solutions/solution-FVSolver",
119 tarch::plotter::griddata::blockstructured::PeanoTextPatchFileWriter::IndexFileMode::AppendNewData,
120 0.5 * (repositories::getMinTimeStamp() + repositories::getMaxTimeStamp())
121 );
122
123 auto dataWriter = writer.createCellDataWriter(
124 "FVSolverQ",
125 AbstractFVSolver::NumberOfFiniteVolumesPerAxisPerPatch,
126 AbstractFVSolver::NumberOfUnknowns,
127 PlotDescription,
128 "",
129 nullptr
130 );
131 dataWriter->setPrecision(PlotterPrecision);
132
133 for (auto& marker : _cells) {
134 const int patchIndex = writer.plotPatch(marker.x() - marker.h() * 0.5, marker.h());
135 int cellIndex = dataWriter->getFirstCellWithinPatch(patchIndex);
136 int currentDoF = 0;
137 double* QOut = DataRepository::getInstance().getCellQ(marker.x(), marker.h());
138 dfor(k, AbstractFVSolver::NumberOfFiniteVolumesPerAxisPerPatch) {
139 double* data = QOut + currentDoF;
140
141 dataWriter->plotCell(cellIndex, data);
142 cellIndex++;
143 currentDoF += AbstractFVSolver::NumberOfUnknowns;
144 }
145 }
146 dataWriter->close();
147 writer.writeToFile();
148 delete dataWriter;
149 repositories::finishPlottingStep();
150}
151
153 const double* NOALIAS Qinside,
154 double* NOALIAS Qoutside,
155 const tarch::la::Vector<DIMENSIONS, double>& x,
156 const tarch::la::Vector<DIMENSIONS, double>& h,
157 double t,
158 double dt,
159 int normal
160) {
161 repositories::instanceOfFVSolver.boundaryConditions(Qinside, Qoutside, x, h, t, normal);
162}
163
164void applyBoundaryConditionsToAxis(int axis, double t, double dt) {
165 const double ratio = DomainSize[0] / CellSize[0];
166 const int depth = static_cast<int>(std::round(std::log(ratio) / std::log(3.0)));
167 dfore(volume, GridLength, axis, 0) {
168 tarch::la::Vector<DIMENSIONS, double> faceOffset = CellSize / 2.0;
169 // --- Low Boundary ---
170 tarch::la::Vector<DIMENSIONS, double>
171 faceCenterLow = tarch::la::multiplyComponents(tarch::la::convertScalar<double>(volume), CellSize) + faceOffset
172 + DomainOffset;
173 int faceIndexLow = DataRepository::Indexing::getFaceIndex(faceCenterLow, CellSize, axis);
174 faceCenterLow[axis] = DomainOffset[axis];
175
176 // --- High Boundary ---
177 tarch::la::Vector<DIMENSIONS, double> faceCenterHigh = faceCenterLow;
178 faceCenterHigh[axis] = DomainSize[axis] - faceOffset[axis] + DomainOffset[axis]; // high cell Centre
179 int faceIndexHigh = DataRepository::Indexing::getFaceIndex(faceCenterHigh, CellSize, axis);
180 faceCenterHigh[axis] = DomainSize[axis] + DomainOffset[axis]; // High face centre
181
182 // Apply BC to low face
183 double* lowFacePtr = DataRepository::getInstance().getFaceQNew(faceIndexLow, axis);
184 ::exahype2::fv::applyBoundaryConditions<double>(
186 faceCenterLow,
187 CellSize,
188 t,
189 dt,
190 AbstractFVSolver::NumberOfFiniteVolumesPerAxisPerPatch,
191 1,
192 AbstractFVSolver::NumberOfUnknowns + AbstractFVSolver::NumberOfAuxiliaryVariables,
193 axis,
194 lowFacePtr
195 );
196
197 // Apply BC to high face
198 double* highFacePtr = DataRepository::getInstance().getFaceQNew(faceIndexHigh, axis + DIMENSIONS);
199 ::exahype2::fv::applyBoundaryConditions<double>(
201 faceCenterHigh,
202 CellSize,
203 t,
204 dt,
205 AbstractFVSolver::NumberOfFiniteVolumesPerAxisPerPatch,
206 1,
207 AbstractFVSolver::NumberOfUnknowns + AbstractFVSolver::NumberOfAuxiliaryVariables,
208 axis + DIMENSIONS,
209 highFacePtr
210 );
211 }
212}
213
215 const double t = 0.0;
216 const double dt = 0.0;
217
218 for (int axis = 0; axis < DIMENSIONS; ++axis) {
220 }
221}
222
224 for (auto& marker : _cells) {
225 double* QOut = DataRepository::getInstance().getCellQ(marker.x(), marker.h());
226 double* faces[TWO_TIMES_D];
227 for (int i = 0; i < TWO_TIMES_D; i++) {
228 faces[i] = DataRepository::getInstance().getFaceQNew(marker.x(), marker.h(), i);
229 }
230 toolbox::blockstructured::projectPatchSolutionOntoFaces(
231 AbstractFVSolver::NumberOfFiniteVolumesPerAxisPerPatch,
232 1,
233 AbstractFVSolver::NumberOfUnknowns,
234 AbstractFVSolver::NumberOfAuxiliaryVariables,
235 QOut,
236 faces
237 );
238 }
239}
240
242 for (auto& marker : _cells) {
243 double* QOut = DataRepository::getInstance().getCellQ(marker.x(), marker.h());
244 // Initialise cell data with initial conditions.
245 dfor(volume, AbstractFVSolver::NumberOfFiniteVolumesPerAxisPerPatch) {
246 int linearIndex = peano4::utils::dLinearised(volume, AbstractFVSolver::NumberOfFiniteVolumesPerAxisPerPatch)
247 * (AbstractFVSolver::NumberOfUnknowns + AbstractFVSolver::NumberOfAuxiliaryVariables);
248 FVSolver::initialCondition(
249 QOut + linearIndex,
250 ::exahype2::fv::
251 getVolumeCentre(marker.x(), marker.h(), AbstractFVSolver::NumberOfFiniteVolumesPerAxisPerPatch, volume),
252 ::exahype2::fv::getVolumeSize(marker.h(), AbstractFVSolver::NumberOfFiniteVolumesPerAxisPerPatch),
253 true
254 );
255 }
256 }
257}
258
259peano4::datamanagement::CellMarker createMarkerFromIndex(const tarch ::la ::Vector<DIMENSIONS, int>& index) {
260 tarch::la::Vector<DIMENSIONS, double> cellIndex = tarch::la::convertScalar<double>(index);
261 tarch::la::Vector<DIMENSIONS, double> cellPositionBase = DomainOffset + CellSize / 2.0;
262 tarch::la::Vector<DIMENSIONS, double>
263 cellPosition = cellPositionBase + tarch::la::multiplyComponents(cellIndex, CellSize);
264 peano4::grid::GridTraversalEvent event;
265 event.setX(cellPosition);
266 event.setH(CellSize);
267 return peano4::datamanagement::CellMarker(event);
268}
269
271 repositories::startGridConstructionStep();
272 _cells.reserve(std::pow(GridLength, DIMENSIONS));
273 dfor(volume, GridLength) { _cells.push_back(createMarkerFromIndex(volume)); }
274 repositories::finishGridConstructionStep();
275}
276
277void initGrid() {
278 repositories::startGridInitialisationStep();
281 repositories::finishGridInitialisationStep();
282}
283
284int main(int argc, char** argv) {
285 int returnCode = EXIT_SUCCESS;
286
287 peano4::init(
288 &argc,
289 &argv,
290 benchmarks::exahype2::kernelbenchmarks::DomainOffset,
291 benchmarks::exahype2::kernelbenchmarks::DomainSize
292 );
293
294 repositories::initLogFilters();
295 repositories::startSimulation();
296
297 createGrid();
298 logInfo("main()", "Created grid with " << _cells.size() << " cells");
299 initGrid();
300 logInfo("main()", "Initialised grid");
301
303
304 {
305 ::exahype2::CellData<double, double, 3> patchData(_cells.size(), tarch::MemoryLocation::Pinned);
306
307 double* QInFlattened = tarch::allocateMemory<double>(
308 _cells.size() * grid.getCellQReconstructedCardinality(),
309 tarch::MemoryLocation::Pinned
310 );
311
312 double* QOutFlattened = tarch::allocateMemory<double>(
313 _cells.size() * grid.getCellQCardinality(),
314 tarch::MemoryLocation::Pinned
315 );
316 double* QOutFlattenedHost = grid.getCellQ(0);
317
318 tarch::la::Vector<DIMENSIONS, double>* cellCentresHost = new tarch::la::Vector<DIMENSIONS, double>[_cells.size()];
319 tarch::la::Vector<DIMENSIONS, double>* cellSizeHost = new tarch::la::Vector<DIMENSIONS, double>[_cells.size()];
320
321 for (int patchIndex = 0; patchIndex < _cells.size(); patchIndex++) {
322 cellCentresHost[patchIndex] = _cells[patchIndex].x();
323 cellSizeHost[patchIndex] = _cells[patchIndex].h();
324 for (int type = 0; type < 3; type++) {
325 for (int face = 0; face < TWO_TIMES_D; face++) {
326 patchData.faces[patchIndex][type][face] = grid.getFaceQNewDevice(
327 _cells[patchIndex].x(),
328 _cells[patchIndex].h(),
329 face
330 );
331 }
332 }
333 }
334 tarch::copyTo<tarch::la::Vector<DIMENSIONS, double>, tarch::la::Vector<DIMENSIONS, double>>(
335 patchData.cellCentre,
336 cellCentresHost,
337 _cells.size(),
338 tarch::MemoryLocation::Pinned
339 );
340 tarch::copyTo<tarch::la::Vector<DIMENSIONS, double>, tarch::la::Vector<DIMENSIONS, double>>(
341 patchData.cellSize,
342 cellSizeHost,
343 _cells.size(),
344 tarch::MemoryLocation::Pinned
345 );
346
347 tarch::copyTo<double, double>(
348 QOutFlattened,
349 QOutFlattenedHost,
350 _cells.size() * grid.getCellQCardinality(),
351 tarch::MemoryLocation::Pinned
352 );
353
354 patchData.QOutFlattened = QOutFlattened;
355 patchData.QInFlattened = QInFlattened;
356
357 tarch::timing::Measurement measurement(1.0);
358 tarch::timing::Watch timeStepWatch("::", "main()", false);
359 double timeStamp = 0.0;
360 double nextMinPlotTimeStamp = FirstPlotTimeStamp;
361 double nextMaxPlotTimeStamp = FirstPlotTimeStamp;
362 bool continueToSolve = true;
363
364 while (continueToSolve) {
365 if (repositories::getMinTimeStamp() >= nextMinPlotTimeStamp
366 or repositories::getMaxTimeStamp() >= nextMaxPlotTimeStamp) {
367 if (repositories::getMinTimeStamp() >= nextMinPlotTimeStamp) {
368 nextMinPlotTimeStamp += TimeInBetweenPlots;
369 }
370 if (repositories::getMaxTimeStamp() >= nextMaxPlotTimeStamp) {
371 nextMaxPlotTimeStamp += TimeInBetweenPlots;
372 }
373
374 if constexpr (ShouldPlot) {
375 plotGrid();
376 }
377 }
378
379 timeStepWatch.start();
380
382 grid.copyFacesToDevice();
383
384 patchData.t = timeStamp;
385 patchData.dt = repositories::instanceOfFVSolver.getAdmissibleTimeStepSize();
386 repositories::startTimeStep();
387
388 tarch::timing::Watch watch("", "", false);
389 benchmarks::exahype2::kernelbenchmarks::tasks::FVSolverEnclaveTask::fuse(patchData);
390 watch.stop();
391 measurement.setValue(watch.getCalendarTime());
392
393 timeStamp += repositories::instanceOfFVSolver.getAdmissibleTimeStepSize();
394 repositories::finishTimeStep();
395
396 tarch::copyFrom<double, double>(
397 QOutFlattened,
398 QOutFlattenedHost,
399 _cells.size() * grid.getCellQCardinality(),
400 tarch::MemoryLocation::Pinned
401 );
402
403 grid.copyFacesFromDevice();
404 timeStepWatch.stop();
405 timeStepMeasurement.setValue(timeStepWatch.getCalendarTime());
406
407 if (timeStepMeasurement.getAccumulatedValue() >= printNextTimeStep) {
408 repositories::printTimeStep(false);
409 if (timeStepMeasurement.getNumberOfMeasurements() > 0) {
410 logInfo("main()", "Average cell updates per second: " << _cells.size() / measurement.getValue());
411 }
412 printNextTimeStep += repositories::PrintTimeStepIntervalInSeconds;
413 }
414
415 if (repositories::getMinTimeStamp() >= MinTerminalTime and repositories::getMaxTimeStamp() >= MaxTerminalTime) {
416 continueToSolve = false;
417 }
418
419 if (tarch::hasNonCriticalAssertionBeenViolated() and not haveReceivedNonCriticalAssertion) {
420 continueToSolve = false;
421 haveReceivedNonCriticalAssertion = true;
422 logError("main()", "Noncritical assertion has been triggered in code. Dump final state and terminate.");
423 }
424 }
425
426 // Plot last timestep
427 if constexpr (ShouldPlot) {
428 plotGrid();
429 }
430 repositories::finishSimulation();
431
432 if (haveReceivedNonCriticalAssertion) {
433 logWarning("main()", "Terminated gracefully after noncritical assertion");
434 returnCode = EXIT_FAILURE;
435 } else {
436 // Print final timestep information
437 repositories::printTimeStep(false);
438 logInfo("main()", "Terminated successfully");
439 returnCode = EXIT_SUCCESS;
440 }
441
442 reportRuntime(measurement);
443
444 delete[] cellCentresHost;
445 delete[] cellSizeHost;
446 tarch::freeMemory(QOutFlattened, tarch::MemoryLocation::Pinned);
447 tarch::freeMemory(QInFlattened, tarch::MemoryLocation::Pinned);
448 }
449
450 peano4::shutdown();
451
452 return returnCode;
453}
constexpr double timeStamp
const tarch::la::Vector< DIMENSIONS, double > CellSize
tarch::timing::Measurement timeStepMeasurement
Definition ccz4-main.cpp:58
tarch::logging::Log _log("::")
A singleton repository to manage and provide access to grid cell and face data.
peano4::datamanagement::CellMarker createMarkerFromIndex(const tarch ::la ::Vector< DIMENSIONS, int > &index)
void applyBoundaryConditionsToAxis(int axis, double t, double dt)
void applyBoundaryConditions()
int main(int argc, char **argv)
void applyInitialConditions()
void initGrid()
void plotGrid()
void invokeFVSolverBoundaryConditions(const double *NOALIAS Qinside, double *NOALIAS Qoutside, const tarch::la::Vector< DIMENSIONS, double > &x, const tarch::la::Vector< DIMENSIONS, double > &h, double t, double dt, int normal)
void createGrid()
void projectPatchOntoFaces()
void reportRuntime(const std::string &kernelIdentificator, const tarch::timing::Measurement &timingComputeKernel, const tarch::timing::Measurement &timingKernelLaunch, int numberOfCells, int numberOfThreads, tarch::logging::Log _log)
Reports the runtime and throughput of the benchmarks.
Definition Utils.h:68
Definition grid.py:1
static int getFaceIndex(const tarch::la::Vector< DIMENSIONS, double > &cellCentre, const tarch::la::Vector< DIMENSIONS, double > &cellSize, int axis)