AutoPas  3.0.0
Loading...
Searching...
No Matches
LiveInfo.h
Go to the documentation of this file.
1
7#pragma once
8
9#include <algorithm>
10#include <cmath>
11#include <cstddef>
12#include <limits>
13#include <variant>
14
24#include "autopas/utils/Timer.h"
26
27namespace autopas {
28
33class LiveInfo {
34 // The class currently needs to be defined in a header only since iteration over a particle container requires to
35 // know the Particle type. Actually, no particle specific information can be used here, so only a pointer to
36 // ParticleBase would suffice, but iteration doesn't work that way at the moment.
37
38 private:
49 static utils::ParticleBinStructure buildCellBinStructure(const std::array<double, 3> &domainSize,
50 const double interactionLength,
51 const std::array<double, 3> &boxMin,
52 const std::array<double, 3> &boxMax, double cutoff) {
53 std::array<size_t, 3> cellsPerDim{};
54 std::array<double, 3> cellLength{};
55
56 for (int d = 0; d < 3; ++d) {
57 // The number of cells is rounded down because the cells will be stretched to fit.
58 // std::max to ensure there is at least one cell.
59 cellsPerDim[d] = std::max(static_cast<size_t>(std::floor(domainSize[d] / interactionLength)), 1ul);
60 cellLength[d] = domainSize[d] / static_cast<double>(cellsPerDim[d]);
61 }
62
63 return {cellsPerDim, cellLength, boxMin, boxMax, cutoff};
64 }
65
79 static utils::ParticleBinStructure buildParticleDependentBinStructure(const std::array<double, 3> &domainSize,
80 const size_t numParticles,
81 const std::array<double, 3> &boxMin,
82 const std::array<double, 3> &boxMax,
83 double cutoff) {
84 using namespace autopas::utils::ArrayMath::literals;
85
86 const auto targetNumberOfBins = std::max(std::ceil(static_cast<double>(numParticles) / 10.), 1.);
87 const auto targetNumberOfBinsPerDim = std::cbrt(targetNumberOfBins);
88 // This is probably not an integer, so we floor to get more than 10 particles per bin
89 const auto numberOfBinsPerDim = static_cast<size_t>(std::floor(targetNumberOfBinsPerDim));
90 const auto binDimensions = domainSize / static_cast<double>(numberOfBinsPerDim);
91
92 return {numberOfBinsPerDim, binDimensions, boxMin, boxMax, cutoff};
93 }
94
104 static utils::ParticleBinStructure buildBlurredBinStructure(const std::array<double, 3> &domainSize,
105 const std::array<double, 3> &boxMin,
106 const std::array<double, 3> &boxMax, double cutoff) {
107 using namespace autopas::utils::ArrayMath::literals;
108
109 const auto binLength = domainSize / 3.;
110
111 return {3, binLength, boxMin, boxMax, cutoff};
112 }
113
114 public:
118 using InfoType = std::variant<bool, double, size_t, ContainerOption, TraversalOption, LoadEstimatorOption,
119 DataLayoutOption, Newton3Option>;
120
124 LiveInfo() = default;
125
163 LiveInfo(size_t numOwnedParticles, size_t numHaloParticles, double cutoff, double skin, double domainSizeX,
164 double domainSizeY, double domainSizeZ, size_t particleSize, size_t threadCount, size_t rebuildFrequency,
165 size_t numCells, size_t numEmptyCells, size_t minParticlesPerCell, size_t maxParticlesPerCell,
166 size_t medianParticlesPerCell, size_t lowerQuartileParticlesPerCell, size_t upperQuartileParticlesPerCell,
167 double meanParticlesPerCell, double particlesPerCellStdDev, double relativeParticlesPerCellStdDev,
168 size_t estimatedNumNeighborInteractions, double particleDependentBinMaxDensity,
169 double particleDependentBinDensityStdDev, size_t maxParticlesPerBlurredBin, size_t minParticlesPerBlurredBin,
170 size_t medianParticlesPerBlurredBin, size_t lowerQuartileParticlesPerBlurredBin,
171 size_t upperQuartileParticlesPerBlurredBin, double meanParticlesPerBlurredBin,
172 double particlesPerBlurredBinStdDev, double relativeParticlesPerBlurredBinStdDev) {
173 // Validate all inputs and log warnings if invalid
174 if (cutoff <= 0) {
175 AutoPasLog(WARN, "LiveInfo: cutoff must be greater than 0");
176 }
177 if (skin < 0) {
178 AutoPasLog(WARN, "LiveInfo: skin must be non-negative");
179 }
180 if (domainSizeX <= 0 or domainSizeY <= 0 or domainSizeZ <= 0) {
181 AutoPasLog(WARN, "LiveInfo: domain sizes must be greater than 0");
182 }
183 if (particleSize == 0) {
184 AutoPasLog(WARN, "LiveInfo: particleSize must be greater than 0");
185 }
186 if (threadCount == 0) {
187 AutoPasLog(WARN, "LiveInfo: threadCount must be greater than 0");
188 }
189 if (rebuildFrequency == 0) {
190 AutoPasLog(WARN, "LiveInfo: rebuildFrequency must be greater than 0");
191 }
192 if (numCells == 0) {
193 AutoPasLog(WARN, "LiveInfo: numCells must be greater than 0");
194 }
195 if (maxParticlesPerCell < minParticlesPerCell) {
196 AutoPasLog(WARN, "LiveInfo: maxParticlesPerCell must be >= minParticlesPerCell");
197 }
198 if (meanParticlesPerCell < 0) {
199 AutoPasLog(WARN, "LiveInfo: meanParticlesPerCell must be non-negative");
200 }
201 if (particlesPerCellStdDev < 0) {
202 AutoPasLog(WARN, "LiveInfo: particlesPerCellStdDev must be non-negative");
203 }
204 if (relativeParticlesPerCellStdDev < 0) {
205 AutoPasLog(WARN, "LiveInfo: relativeParticlesPerCellStdDev must be non-negative");
206 }
207 if (particleDependentBinMaxDensity < 0) {
208 AutoPasLog(WARN, "LiveInfo: particleDependentBinMaxDensity must be non-negative");
209 }
210 if (particleDependentBinDensityStdDev < 0) {
211 AutoPasLog(WARN, "LiveInfo: particleDependentBinDensityStdDev must be non-negative");
212 }
213 if (maxParticlesPerBlurredBin < minParticlesPerBlurredBin) {
214 AutoPasLog(WARN, "LiveInfo: maxParticlesPerBlurredBin must be >= minParticlesPerBlurredBin");
215 }
216 if (meanParticlesPerBlurredBin < 0) {
217 AutoPasLog(WARN, "LiveInfo: meanParticlesPerBlurredBin must be non-negative");
218 }
219 if (particlesPerBlurredBinStdDev < 0) {
220 AutoPasLog(WARN, "LiveInfo: particlesPerBlurredBinStdDev must be non-negative");
221 }
222 if (relativeParticlesPerBlurredBinStdDev < 0) {
223 AutoPasLog(WARN, "LiveInfo: relativeParticlesPerBlurredBinStdDev must be non-negative");
224 }
225
226 // Store validated parameters in infos
227 infos["numOwnedParticles"] = numOwnedParticles;
228 infos["numHaloParticles"] = numHaloParticles;
229 infos["cutoff"] = cutoff;
230 infos["skin"] = skin;
231 infos["domainSizeX"] = domainSizeX;
232 infos["domainSizeY"] = domainSizeY;
233 infos["domainSizeZ"] = domainSizeZ;
234 infos["particleSize"] = particleSize;
235 infos["threadCount"] = threadCount;
236 infos["rebuildFrequency"] = rebuildFrequency;
237 infos["numCells"] = numCells;
238 infos["numEmptyCells"] = numEmptyCells;
239 infos["minParticlesPerCell"] = minParticlesPerCell;
240 infos["maxParticlesPerCell"] = maxParticlesPerCell;
241 infos["medianParticlesPerCell"] = medianParticlesPerCell;
242 infos["lowerQuartileParticlesPerCell"] = lowerQuartileParticlesPerCell;
243 infos["upperQuartileParticlesPerCell"] = upperQuartileParticlesPerCell;
244 infos["meanParticlesPerCell"] = meanParticlesPerCell;
245 infos["particlesPerCellStdDev"] = particlesPerCellStdDev;
246 infos["relativeParticlesPerCellStdDev"] = relativeParticlesPerCellStdDev;
247 infos["estimatedNumNeighborInteractions"] = estimatedNumNeighborInteractions;
248 infos["particleDependentBinMaxDensity"] = particleDependentBinMaxDensity;
249 infos["particleDependentBinDensityStdDev"] = particleDependentBinDensityStdDev;
250 infos["maxParticlesPerBlurredBin"] = maxParticlesPerBlurredBin;
251 infos["minParticlesPerBlurredBin"] = minParticlesPerBlurredBin;
252 infos["medianParticlesPerBlurredBin"] = medianParticlesPerBlurredBin;
253 infos["lowerQuartileParticlesPerBlurredBin"] = lowerQuartileParticlesPerBlurredBin;
254 infos["upperQuartileParticlesPerBlurredBin"] = upperQuartileParticlesPerBlurredBin;
255 infos["meanParticlesPerBlurredBin"] = meanParticlesPerBlurredBin;
256 infos["particlesPerBlurredBinStdDev"] = particlesPerBlurredBinStdDev;
257 infos["relativeParticlesPerBlurredBinStdDev"] = relativeParticlesPerBlurredBinStdDev;
258 }
259
327 template <class Particle_T>
328 void gather(ContainerIterator<Particle_T, true, false> particleIter, size_t rebuildFrequency,
329 size_t numOwnedParticles, std::array<double, 3> boxMin, std::array<double, 3> boxMax, double cutoff,
330 double skin) {
331 using namespace utils::ArrayMath::literals;
333
334 // Timer for debugging
335 utils::Timer timerGatherLiveInfo;
336 timerGatherLiveInfo.start();
337
338 // Aliases and info of particle distribution independent information
339 const auto interactionLength = cutoff + skin;
340
341 infos["cutoff"] = cutoff;
342 infos["skin"] = skin;
343 infos["rebuildFrequency"] = rebuildFrequency;
344 infos["particleSize"] = sizeof(Particle_T);
345 infos["threadCount"] = static_cast<size_t>(autopas_get_max_threads());
346
347 infos["numOwnedParticles"] = numOwnedParticles;
348
349 const auto domainSize = boxMax - boxMin;
350 infos["domainSizeX"] = domainSize[0];
351 infos["domainSizeY"] = domainSize[1];
352 infos["domainSizeZ"] = domainSize[2];
353
354 // Build bin structures
355 auto cellBinStruct = buildCellBinStructure(domainSize, interactionLength, boxMin, boxMax, cutoff);
356 auto particleDependentBinStruct =
357 buildParticleDependentBinStructure(domainSize, numOwnedParticles, boxMin, boxMax, cutoff);
358 auto blurredBinStruct = buildBlurredBinStructure(domainSize, boxMin, boxMax, cutoff);
359
360 infos["numCells"] = cellBinStruct.getNumberOfBins();
361
362 // Count the number of owned particles per bin for each bin structure. Also include total count for halo particles.
363 size_t numOwnedParticlesCount = 0;
364 size_t numHaloParticlesCount = 0;
365 for (; particleIter.isValid(); ++particleIter) {
366 if (particleIter->isOwned()) {
367 numOwnedParticlesCount++;
368 const auto particlePos = particleIter->getR();
369 if (utils::inBox(particlePos, boxMin, boxMax)) {
370 cellBinStruct.countParticle(particlePos);
371 particleDependentBinStruct.countParticle(particlePos);
372 blurredBinStruct.countParticle(particlePos);
373 }
374 } else if (particleIter->isHalo()) {
375 numHaloParticlesCount++;
376 }
377 }
378
379 // Sanity Check
380 if (numOwnedParticlesCount != numOwnedParticles) {
381 AutoPasLog(ERROR,
382 "Number of owned particles tracked by AutoPas ({}) does not match number of owned particles "
383 "counted using the iterator ({}).",
384 numOwnedParticles, numOwnedParticlesCount);
385 }
386
387 infos["numOwnedParticles"] = numOwnedParticlesCount;
388 infos["numHaloParticles"] = numHaloParticlesCount;
389
390 // calculate statistics
391 cellBinStruct.calculateStatistics();
392 particleDependentBinStruct.calculateStatistics();
393 blurredBinStruct.calculateStatistics();
394
395 // write cellBinStruct statistics to live info
396 infos["numEmptyCells"] = cellBinStruct.getNumEmptyBins();
397 infos["maxParticlesPerCell"] = cellBinStruct.getMaxParticlesPerBin();
398 infos["minParticlesPerCell"] = cellBinStruct.getMinParticlesPerBin();
399 infos["medianParticlesPerCell"] = cellBinStruct.getMedianParticlesPerBin();
400 infos["lowerQuartileParticlesPerCell"] = cellBinStruct.getLowerQuartileParticlesPerBin();
401 infos["upperQuartileParticlesPerCell"] = cellBinStruct.getUpperQuartileParticlesPerBin();
402 infos["meanParticlesPerCell"] = cellBinStruct.getMeanParticlesPerBin();
403 infos["relativeParticlesPerCellStdDev"] = cellBinStruct.getRelStdDevParticlesPerBin();
404 infos["particlesPerCellStdDev"] = cellBinStruct.getStdDevParticlesPerBin();
405 infos["estimatedNumNeighborInteractions"] = cellBinStruct.getEstimatedNumberOfNeighborInteractions();
406
407 // write particle dependent bin statistics to live info
408 infos["particleDependentBinMaxDensity"] = particleDependentBinStruct.getMaxDensity();
409 infos["particleDependentBinDensityStdDev"] = particleDependentBinStruct.getStdDevDensity();
410
411 // write blurred bin statistics to live info
412 infos["maxParticlesPerBlurredBin"] = blurredBinStruct.getMaxParticlesPerBin();
413 infos["minParticlesPerBlurredBin"] = blurredBinStruct.getMinParticlesPerBin();
414 infos["medianParticlesPerBlurredBin"] = blurredBinStruct.getMedianParticlesPerBin();
415 infos["lowerQuartileParticlesPerBlurredBin"] = blurredBinStruct.getLowerQuartileParticlesPerBin();
416 infos["upperQuartileParticlesPerBlurredBin"] = blurredBinStruct.getUpperQuartileParticlesPerBin();
417 infos["meanParticlesPerBlurredBin"] = blurredBinStruct.getMeanParticlesPerBin();
418 infos["relativeParticlesPerBlurredBinStdDev"] = blurredBinStruct.getRelStdDevParticlesPerBin();
419 infos["particlesPerBlurredBinStdDev"] = blurredBinStruct.getStdDevParticlesPerBin();
420
421 timerGatherLiveInfo.stop();
422 AutoPasLog(DEBUG, "Gathering of LiveInfo took {} ns.", timerGatherLiveInfo.getTotalTime());
423 }
424
429 [[nodiscard]] const auto &get() const { return infos; }
430
437 template <typename T>
438 T get(const std::string &key) const {
439 // Find the key in the map
440 const auto it = infos.find(key);
441
442 // If key is not found, log an error
443 if (it == infos.end()) {
444 AutoPasLog(ERROR, "Key '" + key + "' not found in infos map.");
445 }
446
447 // Use std::get<T> to extract the value of the desired type
448 try {
449 return std::get<T>(it->second);
450 } catch (const std::bad_variant_access &e) {
451 AutoPasLog(ERROR, "Type mismatch for key '" + key + "'. Requested type does not match the stored type.");
452 return T{};
453 }
454 }
455
460 [[nodiscard]] std::string toString() const {
461 auto typeToString = [](auto type) {
462 if constexpr (std::is_same_v<decltype(type), bool> or std::is_same_v<decltype(type), double> or
463 std::is_same_v<decltype(type), size_t>) {
464 return std::to_string(type);
465 } else if constexpr (std::is_base_of_v<Option<decltype(type)>, decltype(type)>) {
466 return type.to_string();
467 }
468 return std::string{"fail"};
469 };
470 auto pairToString = [&](const auto &pair) { return pair.first + "=" + std::visit(typeToString, pair.second); };
471 std::string res{"Live Info: "};
472 if (not infos.empty()) {
473 // We initialize the accumulation with the first element. Hence, the accumulation starts at next(begin).
474 res += std::accumulate(std::next(infos.begin()), infos.end(), pairToString(*infos.begin()),
475 [&](std::string s, const auto &elem) { return std::move(s) + " " + pairToString(elem); });
476 }
477 return res;
478 }
479
486 friend std::ostream &operator<<(std::ostream &out, const LiveInfo &info) {
487 out << info.infos.size() << ' ';
488 for (const auto &[name, val] : info.infos) {
489 // val.index here is the index of this value's type in the LiveInfo::InfoType variant type.
490 // This is needed for determining the type when reading this file via readIndex.
491 out << name << ' ' << val.index() << ' ';
492 std::visit([&](const auto &v) { out << v << ' '; }, val);
493 }
494 return out;
495 }
496
503 friend std::istream &operator>>(std::istream &in, LiveInfo &info) {
504 size_t numElements{0};
505 in >> numElements;
506 for (size_t i = 0; i < numElements; i++) {
507 std::string name;
508 in >> name;
509 size_t idx{0};
510 in >> idx;
511 const auto val =
512 readIndex<LiveInfo::InfoType>(in, idx, std::make_index_sequence<std::variant_size_v<LiveInfo::InfoType>>());
513 info.infos[name] = val;
514 }
515 return in;
516 }
517
523 [[nodiscard]] std::pair<std::string, std::string> getCSVLine() const {
524 // match all words (anything that is neither a ' ' or '='), that are followed by a '=',
525 // ignoring the 'Live Info: ' prefix
526 const auto keyRegex = std::regex("([^= ]+)=[^ ]*");
527 // match all words that are preceded by a '='
528 const auto valueRegex = std::regex("=([^ ]+)");
529
530 auto searchString = toString();
531 // remove leading Live Info:
532 searchString = searchString.substr(std::string("Live Info: ").size());
533
534 std::sregex_iterator keyIter(searchString.begin(), searchString.end(), keyRegex);
535 std::sregex_iterator valueIter(searchString.begin(), searchString.end(), valueRegex);
536 std::sregex_iterator end;
537
538 std::stringstream header;
539 std::stringstream line;
540
541 while (keyIter != end) {
542 // first submatch is the match of the capture group
543 header << keyIter->str(1) << ",";
544 ++keyIter;
545 }
546 while (valueIter != end) {
547 // first submatch is the match of the capture group
548 line << valueIter->str(1) << ",";
549 ++valueIter;
550 }
551
552 auto headerStr = header.str();
553 auto lineStr = line.str();
554 // drop trailing ','
555 headerStr.pop_back();
556 lineStr.pop_back();
557
558 return std::make_pair(headerStr, lineStr);
559 }
560
561 private:
572 template <class Variant, class Type, size_t Idx>
573 static void readIndexHelper(std::istream &in, size_t idx, Variant &var) {
574 if (Idx == idx) {
575 Type val;
576 in >> val;
577 var = val;
578 }
579 }
580
589 template <class Variant, size_t... Idx>
590 static Variant readIndex(std::istream &in, size_t idx, std::index_sequence<Idx...>) {
591 Variant var;
592 (readIndexHelper<Variant, std::variant_alternative_t<Idx, Variant>, Idx>(in, idx, var), ...);
593 return var;
594 }
595
599 std::map<std::string, InfoType> infos;
600};
601
602} // namespace autopas
#define AutoPasLog(lvl, fmt,...)
Macro for logging providing common meta information without filename.
Definition: Logger.h:24
Public iterator class that iterates over a particle container and additional vectors (which are typic...
Definition: ContainerIterator.h:93
bool isValid() const
Check whether the iterator currently points to a valid particle.
Definition: ContainerIterator.h:295
This class is able to gather and store important information for a tuning phase from a container and ...
Definition: LiveInfo.h:33
std::string toString() const
Creates a string containing all live info gathered.
Definition: LiveInfo.h:460
T get(const std::string &key) const
Gets a single value from the infos that corresponds to the given string.
Definition: LiveInfo.h:438
std::pair< std::string, std::string > getCSVLine() const
Generate a csv representation containing all values from the toString() method.
Definition: LiveInfo.h:523
friend std::istream & operator>>(std::istream &in, LiveInfo &info)
Stream operator to read the LiveInfo in from a stream.
Definition: LiveInfo.h:503
friend std::ostream & operator<<(std::ostream &out, const LiveInfo &info)
Stream operator to write the LiveInfo to a stream.
Definition: LiveInfo.h:486
std::variant< bool, double, size_t, ContainerOption, TraversalOption, LoadEstimatorOption, DataLayoutOption, Newton3Option > InfoType
The type of an info.
Definition: LiveInfo.h:119
void gather(ContainerIterator< Particle_T, true, false > particleIter, size_t rebuildFrequency, size_t numOwnedParticles, std::array< double, 3 > boxMin, std::array< double, 3 > boxMax, double cutoff, double skin)
Gathers key statistics that define the computational profile of the simulation, in order to provide l...
Definition: LiveInfo.h:328
LiveInfo()=default
Constructor.
const auto & get() const
Returns a map of all infos.
Definition: LiveInfo.h:429
LiveInfo(size_t numOwnedParticles, size_t numHaloParticles, double cutoff, double skin, double domainSizeX, double domainSizeY, double domainSizeZ, size_t particleSize, size_t threadCount, size_t rebuildFrequency, size_t numCells, size_t numEmptyCells, size_t minParticlesPerCell, size_t maxParticlesPerCell, size_t medianParticlesPerCell, size_t lowerQuartileParticlesPerCell, size_t upperQuartileParticlesPerCell, double meanParticlesPerCell, double particlesPerCellStdDev, double relativeParticlesPerCellStdDev, size_t estimatedNumNeighborInteractions, double particleDependentBinMaxDensity, double particleDependentBinDensityStdDev, size_t maxParticlesPerBlurredBin, size_t minParticlesPerBlurredBin, size_t medianParticlesPerBlurredBin, size_t lowerQuartileParticlesPerBlurredBin, size_t upperQuartileParticlesPerBlurredBin, double meanParticlesPerBlurredBin, double particlesPerBlurredBinStdDev, double relativeParticlesPerBlurredBinStdDev)
Constructor for LiveInfo using the parameters.
Definition: LiveInfo.h:163
Class representing the load estimator choices.
Definition: LoadEstimatorOption.h:18
Particle-counting bin structure.
Definition: ParticleBinStructure.h:34
Timer class to stop times.
Definition: Timer.h:20
void start()
start the timer.
Definition: Timer.cpp:17
long getTotalTime() const
Get total accumulated time.
Definition: Timer.h:53
long stop()
Stops the timer and returns the time elapsed in nanoseconds since the last call to start.
Definition: Timer.cpp:25
constexpr std::array< target_T, SIZE > ceilAndCast(const std::array< float_T, SIZE > &a)
Ceils all array elements and converts them to a different type.
Definition: ArrayMath.h:352
bool inBox(const std::array< T, 3 > &position, const std::array< T, 3 > &low, const std::array< T, 3 > &high)
Checks if position is inside of a box defined by low and high.
Definition: inBox.h:26
This is the main namespace of AutoPas.
Definition: AutoPasDecl.h:32
int autopas_get_max_threads()
Dummy for omp_get_max_threads() when no OpenMP is available.
Definition: WrapOpenMP.h:144
Type
Enum describing all types that are allowed in a rule program.
Definition: RuleBasedProgramTree.h:10