AutoPas  3.0.0
Loading...
Searching...
No Matches
SimilarityFunctions.h
Go to the documentation of this file.
1
7#pragma once
8
13
14namespace autopas::utils {
15
46template <typename Particle>
48 using namespace autopas::utils::ArrayMath::literals;
49
50 const auto numberOfParticles = container.getNumberOfParticles();
51 const auto domainDimensions = container.getBoxMax() - container.getBoxMin();
52 const auto domainVolume = domainDimensions[0] * domainDimensions[1] * domainDimensions[2];
53
54 // We scale the dimensions of the domain to bins with volumes which give approximately 10 particles per bin.
55 // Todo The choice of 10 is arbitrary and probably can be optimized
56 const auto targetNumberOfBins = std::ceil(numberOfParticles / 10.);
57 const auto targetNumberOfBinsPerDim = std::cbrt(static_cast<double>(targetNumberOfBins));
58 // This is probably not an integer, so we floor to get more than 10 particles per bin than too small bins
59 const auto numberOfBinsPerDim = static_cast<int>(std::floor(targetNumberOfBinsPerDim));
60 const auto binDimensions = domainDimensions / static_cast<double>(numberOfBinsPerDim);
61
62 const auto numberOfBins = numberOfBinsPerDim * numberOfBinsPerDim * numberOfBinsPerDim;
63 const auto binVolume = domainVolume / static_cast<double>(numberOfBins);
64
65 std::vector<size_t> particlesPerBin(numberOfBins, 0);
66
67 // add particles accordingly to their bin to get the amount of particles in each bin
68 for (auto particleItr = container.begin(autopas::IteratorBehavior::owned); particleItr.isValid(); ++particleItr) {
69 const auto &particleLocation = particleItr->getR();
70
71 const auto binIndex3dUnsafe =
72 autopas::utils::ArrayMath::floorToInt((particleLocation - container.getBoxMin()) / binDimensions);
73
74 // It is possible that floating point errors result in out of bounds indices.
75 // e.g. if there are 7 bins in the x dimension, and that particle is close to the right domain boundary, the
76 // division above might result in 7.0, which gets floored to 7 corresponding to a bin index that is out of bounds!
77
78 // We therefore check for particle indices that are out of bounds and, if the particle is within the domain we
79 // adjust the index. We don't care about floating point errors causing incorrect indices internally in the
80 // domain as, for particles so close to a boundary, it is somewhat arbitrary which bin they fall into.
81
82 const auto binIndex3DSafe = [&]() {
83 auto newBinIndex3D = binIndex3dUnsafe;
84 for (int dim = 0; dim < 3; ++dim) {
85 if (particleLocation[dim] > container.getBoxMin()[dim] or particleLocation[dim] < container.getBoxMax()[dim]) {
86 newBinIndex3D[dim] = std::clamp(binIndex3dUnsafe[dim], 0, numberOfBinsPerDim - 1);
87 } else {
89 "calculateHomogeneityAndMaxDensity: Particle is outside the container!");
90 }
91 }
92 return newBinIndex3D;
93 }();
94
96 binIndex3DSafe, {numberOfBinsPerDim, numberOfBinsPerDim, numberOfBinsPerDim});
97
98 particlesPerBin[binIndex1d] += 1;
99 }
100
101 // calculate density for each bin and track max density
102 double maxDensity{0.};
103 std::vector<double> densityPerBin{};
104 densityPerBin.reserve(numberOfBins);
105 for (auto i = 0; i < numberOfBins; i++) {
106 densityPerBin.push_back(static_cast<double>(particlesPerBin[i]) / binVolume);
107 maxDensity = std::max(maxDensity, densityPerBin[i]);
108 }
109
110 if (maxDensity < 0.0) {
112 "calculateHomogeneityAndMaxDensity(): maxDensity can never be smaller than 0.0, but is: {}", maxDensity);
113 }
114 // get mean and reserve variable for densityVariance
115 const double densityMean = numberOfParticles / domainVolume;
116
117 const double densityDifferenceSquaredSum = std::transform_reduce(densityPerBin.begin(), densityPerBin.end(), 0.0,
118 std::plus<>(), [densityMean](double density) {
119 double densityDifference = density - densityMean;
120 return densityDifference * densityDifference;
121 });
122
123 const auto densityVariance = densityDifferenceSquaredSum / numberOfBins;
124
125 // finally calculate standard deviation. If there are no particles, the above calculation leads to nan. This should
126 // be forced to 0.
127 const double homogeneity = numberOfParticles == 0 ? 0. : std::sqrt(densityVariance);
128 // normally between 0.0 and 1.5
129 if (homogeneity < 0.0) {
131 "calculateHomogeneityAndMaxDensity(): homogeneity can never be smaller than 0.0, but is: {}", homogeneity);
132 }
133 return {homogeneity, maxDensity};
134}
135
136} // namespace autopas::utils
The ParticleContainerInterface class provides a basic interface for all Containers within AutoPas.
Definition: ParticleContainerInterface.h:37
virtual const std::array< double, 3 > & getBoxMin() const =0
Get the lower corner of the container without halo.
virtual const std::array< double, 3 > & getBoxMax() const =0
Get the upper corner of the container without halo.
virtual ContainerIterator< ParticleType, true, false > begin(IteratorBehavior behavior=autopas::IteratorBehavior::ownedOrHalo, typename ContainerIterator< ParticleType, true, false >::ParticleVecType *additionalVectors=nullptr)=0
Iterate over all particles using for(auto iter = container.begin(); iter.isValid(); ++iter) .
virtual size_t getNumberOfParticles(IteratorBehavior behavior=IteratorBehavior::owned) const =0
Get the number of particles with respect to the specified IteratorBehavior.
static void exception(const Exception e)
Handle an exception derived by std::exception.
Definition: ExceptionHandler.h:63
constexpr std::array< int, SIZE > floorToInt(const std::array< T, SIZE > &a)
Floors all array elements and converts them to integers.
Definition: ArrayMath.h:332
constexpr T threeToOneD(T x, T y, T z, const std::array< T, 3 > &dims)
Convert a 3d index to a 1d index.
Definition: ThreeDimensionalMapping.h:29
In this namespace some helper classes and functions can be found used inside of AutoPas.
Definition: namespaces.h:44
std::pair< double, double > calculateHomogeneityAndMaxDensity(const ParticleContainerInterface< Particle > &container)
Calculates homogeneity and max density of given AutoPas container.
Definition: SimilarityFunctions.h:47