55template <
class Particle_T>
89 VerletClusterLists(
const std::array<double, 3> &boxMin,
const std::array<double, 3> &boxMax,
double cutoff,
90 double skin,
unsigned int rebuildFrequency,
size_t clusterSize,
93 _towerBlock{boxMin, boxMax, cutoff + skin},
94 _clusterSize{clusterSize},
97 _rebuildFrequency{rebuildFrequency},
98 _loadEstimator(loadEstimator) {
100 _towerBlock.addTower(_clusterSize);
105 [[nodiscard]] ContainerOption
getContainerType()
const override {
return ContainerOption::verletClusterLists; }
115 return [&](
const std::array<unsigned long, 3> &cellsPerDimension,
116 const std::array<unsigned long, 3> &lowerCorner,
const std::array<unsigned long, 3> &upperCorner) {
118 unsigned long sum = 0;
119 for (
unsigned long x = lowerCorner[0]; x <= upperCorner[0]; x++) {
120 for (
unsigned long y = lowerCorner[1]; y <= upperCorner[1]; y++) {
121 unsigned long cellLoad = 0;
122 auto &tower = _towerBlock.getTowerByIndex2D(x, y);
123 for (
auto &cluster : tower.getClusters()) {
124 if (cluster.getNeighbors()) {
125 cellLoad += cluster.getNeighbors()->size();
138 [&](
const std::array<unsigned long, 3> &cellsPerDimension,
const std::array<unsigned long, 3> &lowerCorner,
139 const std::array<unsigned long, 3> &upperCorner) {
return 1; };
145 if (_isValid == ValidityState::cellsAndListsValid) {
147 "VerletClusterLists::computeInteractions(): Trying to do a pairwise iteration, even though verlet lists are "
152 if (traversalInterface) {
154 traversalInterface->setTowers(_towerBlock.getTowersRef());
157 "Trying to use a traversal of wrong type in VerletClusterLists::computeInteractions. TraversalID: {}",
169 void reserve(
size_t numParticles,
size_t numParticlesHaloEstimate)
override {
170 const auto particlesPerTower = (numParticles + numParticlesHaloEstimate) / _towerBlock.size();
171 for (
auto &tower : _towerBlock) {
172 tower.reserve(particlesPerTower);
182 _isValid.store(ValidityState::invalid, std::memory_order::memory_order_relaxed);
187 _isValid.store(ValidityState::invalid, std::memory_order::memory_order_relaxed);
192 using namespace autopas::utils::ArrayMath::literals;
194 const auto &haloPos = haloParticle.getR();
197 IteratorBehavior::halo | IteratorBehavior::forceSequential,
nullptr);
198 it.isValid(); ++it) {
199 if (haloParticle.getID() == it->getID()) {
203 it->setV(haloParticle.getV());
204 it->setF(haloParticle.getF());
213 for (
auto &particleVec : _particlesToAdd) {
214 for (
size_t j = 0; j < particleVec.size();) {
215 if (particleVec[j].isHalo()) {
216 particleVec[j] = particleVec[particleVec.size() - 1];
217 particleVec.pop_back();
224 bool deletedSomething =
false;
227 for (
size_t i = 0; i < _towerBlock.size(); ++i) {
228 auto &tower = _towerBlock[i];
229 const auto towerSize = tower.size();
230 auto numTailDummies = tower.getNumTailDummyParticles();
232 for (
size_t j = 0; numTailDummies < towerSize and j < towerSize - numTailDummies;) {
233 if (tower[j].isHalo()) {
235 tower[j] = tower[towerSize - 1 - numTailDummies];
239 deletedSomething =
true;
245 if (deletedSomething) {
246 tower.deleteDummyParticles();
249 if (deletedSomething) {
250 _isValid.store(ValidityState::invalid, std::memory_order::memory_order_relaxed);
254 std::tuple<const Particle_T *, size_t, size_t>
getParticle(
size_t cellIndex,
size_t particleIndex,
255 IteratorBehavior iteratorBehavior,
256 const std::array<double, 3> &boxMin,
257 const std::array<double, 3> &boxMax)
const override {
258 return getParticleImpl<true>(cellIndex, particleIndex, iteratorBehavior, boxMin, boxMax);
260 std::tuple<const Particle_T *, size_t, size_t>
getParticle(
size_t cellIndex,
size_t particleIndex,
261 IteratorBehavior iteratorBehavior)
const override {
263 constexpr std::array<double, 3> boxMin{std::numeric_limits<double>::lowest(), std::numeric_limits<double>::lowest(),
264 std::numeric_limits<double>::lowest()};
266 constexpr std::array<double, 3> boxMax{std::numeric_limits<double>::max(), std::numeric_limits<double>::max(),
267 std::numeric_limits<double>::max()};
268 return getParticleImpl<false>(cellIndex, particleIndex, iteratorBehavior, boxMin, boxMax);
282 template <
bool regionIter>
283 std::tuple<const Particle_T *, size_t, size_t>
getParticleImpl(
size_t cellIndex,
size_t particleIndex,
284 IteratorBehavior iteratorBehavior,
285 const std::array<double, 3> &boxMin,
286 const std::array<double, 3> &boxMax)
const {
287 using namespace autopas::utils::ArrayMath::literals;
291 if (_towerBlock.empty()) {
292 return {
nullptr, 0, 0};
295 std::array<double, 3> boxMinWithSafetyMargin = boxMin;
296 std::array<double, 3> boxMaxWithSafetyMargin = boxMax;
297 if constexpr (regionIter) {
304 const auto [startCellIndex, endCellIndex] = [&]() -> std::tuple<size_t, size_t> {
305 if constexpr (regionIter) {
307 return {_towerBlock.getTowerIndex1DAtPosition(boxMinWithSafetyMargin),
308 _towerBlock.getTowerIndex1DAtPosition(boxMaxWithSafetyMargin)};
310 if (not(iteratorBehavior & IteratorBehavior::halo)) {
312 return {_towerBlock.getFirstOwnedTowerIndex(), _towerBlock.getLastOwnedTowerIndex()};
315 return {0, _towerBlock.size() - 1};
321 if (cellIndex == 0 and particleIndex == 0) {
326 if (cellIndex >= _towerBlock.size()) {
327 return {
nullptr, 0, 0};
330 if (particleIndex >= _towerBlock[cellIndex].getNumActualParticles() or
331 not containerIteratorUtils::particleFulfillsIteratorRequirements<regionIter>(
332 _towerBlock[cellIndex][particleIndex], iteratorBehavior, boxMin, boxMax)) {
334 std::tie(cellIndex, particleIndex) =
335 advanceIteratorIndices<regionIter>(cellIndex, particleIndex, iteratorBehavior, boxMin, boxMax,
336 boxMinWithSafetyMargin, boxMaxWithSafetyMargin, endCellIndex);
339 if (cellIndex > endCellIndex) {
340 return {
nullptr, 0, 0};
342 const Particle_T *retPtr = &_towerBlock[cellIndex][particleIndex];
344 return {retPtr, cellIndex, particleIndex};
359 [[nodiscard]] std::vector<Particle_T>
updateContainer(
bool keepNeighborListsValid)
override {
360 if (keepNeighborListsValid) {
367 for (
size_t i = 0ul; i < _towerBlock.size(); ++i) {
368 _towerBlock[i].deleteDummyParticles();
372 std::vector<Particle_T> invalidParticles;
376 vecMergeParticle : std::vector<Particle_T> : omp_out.insert(omp_out.end(), omp_in.begin(), omp_in.end())))
377 AUTOPAS_OPENMP(parallel reduction(vecMergeParticle : invalidParticles)) {
378 for (
auto iter = this->
begin(IteratorBehavior::owned); iter.isValid(); ++iter) {
380 invalidParticles.push_back(*iter);
385 _isValid.store(ValidityState::invalid, std::memory_order::memory_order_relaxed);
386 return invalidParticles;
390 using namespace autopas::utils::ArrayMath::literals;
393 const auto [towerSideLength, towersPerDim] = _towerBlock.estimateOptimalGridSideLength(
395 const std::array<double, 3> towerSize = {towerSideLength[0], towerSideLength[1],
397 const std::array<unsigned long, 3> towerDimensions = {towersPerDim[0], towersPerDim[1], 1};
405 IteratorBehavior behavior = autopas::IteratorBehavior::ownedOrHalo,
409 if (_isValid != ValidityState::invalid) {
414 "VerletClusterLists::begin(): Error: particle container is valid, but _particlesToAdd isn't empty!");
423 appendBuffersHelper(additionalVectors, additionalVectorsToPass);
433 IteratorBehavior behavior = autopas::IteratorBehavior::ownedOrHalo,
435 nullptr)
const override {
438 if (_isValid != ValidityState::invalid) {
443 "VerletClusterLists::begin() const: Error: particle container is valid, but _particlesToAdd isn't empty!");
452 appendBuffersHelper(additionalVectors, additionalVectorsToPass);
460 template <
typename Lambda>
461 void forEach(Lambda forEachLambda, IteratorBehavior behavior = autopas::IteratorBehavior::ownedOrHalo) {
462 for (
auto &tower : _towerBlock) {
463 tower.forEach(forEachLambda, behavior);
465 for (
auto &vector : this->_particlesToAdd) {
466 for (
auto &particle : vector) {
467 if (behavior.contains(particle)) {
468 forEachLambda(particle);
479 template <
typename Lambda>
480 void forEach(Lambda forEachLambda, IteratorBehavior behavior = autopas::IteratorBehavior::ownedOrHalo)
const {
481 if (_isValid != ValidityState::invalid) {
482 if (not particlesToAddEmpty()) {
484 "VerletClusterLists::forEach() const: Error: particle container is valid, but _particlesToAdd isn't "
490 for (
auto &tower : _towerBlock) {
491 tower.forEach(forEachLambda, behavior);
495 if (_isValid == ValidityState::invalid) {
496 for (
auto &particlesToAddPerThread : _particlesToAdd) {
497 for (
auto &particle : particlesToAddPerThread) {
498 if (behavior.contains(particle)) {
499 forEachLambda(particle);
509 template <
typename Lambda,
typename A>
510 void reduce(Lambda reduceLambda, A &result, IteratorBehavior behavior = autopas::IteratorBehavior::ownedOrHalo) {
511 for (
auto &tower : _towerBlock) {
512 tower.reduce(reduceLambda, result, behavior);
514 for (
auto &vector : this->_particlesToAdd) {
515 for (
auto &p : vector) {
516 if (behavior.contains(p)) {
517 reduceLambda(p, result);
528 template <
typename Lambda,
typename A>
529 void reduce(Lambda reduceLambda, A &result,
530 IteratorBehavior behavior = autopas::IteratorBehavior::ownedOrHalo)
const {
531 if (_isValid != ValidityState::invalid) {
532 if (not particlesToAddEmpty()) {
534 "VerletClusterLists::reduce() const: Error: particle container is valid, but _particlesToAdd isn't empty!");
539 for (
auto tower : _towerBlock) {
540 tower.reduce(reduceLambda, result, behavior);
543 if (_isValid == ValidityState::invalid) {
545 for (
auto &particlesToAddPerThread : _particlesToAdd) {
546 for (
auto &particle : particlesToAddPerThread) {
547 if (behavior.contains(particle)) {
548 reduceLambda(particle, result);
559 const std::array<double, 3> &lowerCorner,
const std::array<double, 3> &higherCorner, IteratorBehavior behavior,
563 if (_isValid != ValidityState::invalid) {
568 "VerletClusterLists::reduce() const: Error: particle container is valid, but _particlesToAdd isn't empty!");
577 appendBuffersHelper(additionalVectors, additionalVectorsToPass);
588 const std::array<double, 3> &lowerCorner,
const std::array<double, 3> &higherCorner, IteratorBehavior behavior,
590 nullptr)
const override {
593 if (_isValid != ValidityState::invalid) {
598 "VerletClusterLists::getRegionIterator() const: Error: particle container is valid, but _particlesToAdd "
608 appendBuffersHelper(additionalVectors, additionalVectorsToPass);
617 template <
typename Lambda>
619 const std::array<double, 3> &higherCorner,
620 IteratorBehavior behavior = autopas::IteratorBehavior::ownedOrHalo) {
621 for (
size_t i = 0; i < _towerBlock.size(); ++i) {
622 if (_towerBlock.ignoreCellForIteration(i, behavior)) {
625 auto &tower = _towerBlock[i];
626 const auto [towerLowCorner, towerHighCorner] = _towerBlock.getTowerBoundingBox(i);
630 if (
utils::boxesOverlap(towerLowCornerSkin, towerHighCornerSkin, lowerCorner, higherCorner)) {
631 tower.forEach(forEachLambda, lowerCorner, higherCorner, behavior);
634 for (
auto &vector : _particlesToAdd) {
635 for (
auto &particle : vector) {
636 if (behavior.contains(particle)) {
637 if (
utils::inBox(particle.getR(), lowerCorner, higherCorner)) {
638 forEachLambda(particle);
650 template <
typename Lambda>
652 const std::array<double, 3> &higherCorner,
653 IteratorBehavior behavior = autopas::IteratorBehavior::ownedOrHalo)
const {
654 if (_isValid != ValidityState::invalid) {
655 if (not particlesToAddEmpty()) {
657 "VerletClusterLists::forEachInRegion() const: Error: particle container is valid, but _particlesToAdd "
663 for (
size_t i = 0; i < _towerBlock.size(); ++i) {
664 if (_towerBlock.ignoreCellForIteration(i, behavior)) {
667 auto &tower = _towerBlock[i];
668 const auto [towerLowCorner, towerHighCorner] = _towerBlock.getTowerBoundingBox(i);
672 if (
utils::boxesOverlap(towerLowCornerSkin, towerHighCornerSkin, lowerCorner, higherCorner)) {
673 tower.forEach(forEachLambda, lowerCorner, higherCorner, behavior);
677 if (_isValid == ValidityState::invalid) {
679 for (
auto &particlesToAddPerThread : _particlesToAdd) {
680 for (
auto &particle : particlesToAddPerThread) {
681 if (behavior.contains(particle)) {
682 if (
utils::inBox(particle.getR(), lowerCorner, higherCorner)) {
683 forEachLambda(particle);
694 template <
typename Lambda,
typename A>
695 void reduceInRegion(Lambda reduceLambda, A &result,
const std::array<double, 3> &lowerCorner,
696 const std::array<double, 3> &higherCorner,
697 IteratorBehavior behavior = autopas::IteratorBehavior::ownedOrHalo) {
698 for (
size_t i = 0; i < _towerBlock.size(); ++i) {
699 if (_towerBlock.ignoreCellForIteration(i, behavior)) {
702 auto &tower = _towerBlock[i];
703 const auto [towerLowCorner, towerHighCorner] = _towerBlock.getTowerBoundingBox(i);
707 if (
utils::boxesOverlap(towerLowCornerSkin, towerHighCornerSkin, lowerCorner, higherCorner)) {
708 tower.reduce(reduceLambda, result, lowerCorner, higherCorner, behavior);
711 for (
auto &vector : _particlesToAdd) {
712 for (
auto &particle : vector) {
713 if (behavior.contains(particle)) {
714 if (
utils::inBox(particle.getR(), lowerCorner, higherCorner)) {
715 reduceLambda(particle, result);
727 template <
typename Lambda,
typename A>
728 void reduceInRegion(Lambda reduceLambda, A &result,
const std::array<double, 3> &lowerCorner,
729 const std::array<double, 3> &higherCorner,
730 IteratorBehavior behavior = autopas::IteratorBehavior::ownedOrHalo)
const {
731 if (_isValid != ValidityState::invalid) {
732 if (not particlesToAddEmpty()) {
734 "VerletClusterLists::reduceInRegion() const: Error: particle container is valid, but _particlesToAdd isn't "
739 for (
size_t i = 0; i < _towerBlock.size(); ++i) {
740 if (_towerBlock.ignoreCellForIteration(i, behavior)) {
743 auto &tower = _towerBlock[i];
744 const auto [towerLowCorner, towerHighCorner] = _towerBlock.getTowerBoundingBox(i);
748 if (
utils::boxesOverlap(towerLowCornerSkin, towerHighCornerSkin, lowerCorner, higherCorner)) {
749 tower.reduce(reduceLambda, result, lowerCorner, higherCorner, behavior);
753 if (_isValid == ValidityState::invalid) {
755 for (
auto &particlesToAddPerThread : _particlesToAdd) {
756 for (
auto &particle : particlesToAddPerThread) {
757 if (behavior.contains(particle)) {
758 if (
utils::inBox(particle.getR(), lowerCorner, higherCorner)) {
759 reduceLambda(particle, result);
770 if (_isValid == ValidityState::invalid or traversal->
getUseNewton3() != _builder->getNewton3()) {
772 _neighborLists.clear();
775 _builder->rebuildNeighborListsAndFillClusters();
778 if (clusterTraversalInterface) {
779 if (clusterTraversalInterface->needsStaticClusterThreadPartition()) {
784 "Trying to use a traversal of wrong type in VerletClusterLists::rebuildNeighborLists. TraversalID: {}",
796 template <
bool inParallel,
class LoopBody>
799 traverseClustersParallel<LoopBody>(std::forward<LoopBody>(loopBody));
801 traverseClustersSequential<LoopBody>(std::forward<LoopBody>(loopBody));
809 [[nodiscard]]
size_t size()
const override {
810 size_t sum = std::accumulate(_towerBlock.begin(), _towerBlock.end(), 0,
811 [](
size_t acc,
const auto &tower) { return acc + tower.size(); });
812 sum = std::accumulate(_particlesToAdd.begin(), _particlesToAdd.end(), sum,
813 [](
size_t acc,
const auto &buffer) { return acc + buffer.size(); });
822 size_t sum = std::accumulate(_towerBlock.begin(), _towerBlock.end(), 0, [&behavior](
size_t acc,
const auto &tower) {
823 return acc + tower.getNumberOfParticles(behavior);
830 sum = std::accumulate(
831 _particlesToAdd.begin(), _particlesToAdd.end(), sum, [&behavior](
size_t acc,
const auto &buffer) {
833 (std::count_if(buffer.begin(), buffer.end(), [&behavior](auto p) { return behavior.contains(p); }));
880 template <
class Functor>
882 const auto numTowers = _towerBlock.size();
885 for (
size_t index = 0; index < numTowers; index++) {
886 _towerBlock[index].loadSoA(functor);
895 template <
class Functor>
897 const auto numTowers = _towerBlock.size();
900 for (
size_t index = 0; index < numTowers; index++) {
901 _towerBlock[index].extractSoA(functor);
912 return _towerBlock.getTowerByIndex2D(x, y);
924 [[nodiscard]]
const std::array<double, 3> &
getBoxMax()
const override {
return _towerBlock.getBoxMax(); }
930 [[nodiscard]]
const std::array<double, 3> &
getHaloBoxMax()
const {
return _towerBlock.getHaloBoxMax(); }
932 [[nodiscard]]
const std::array<double, 3> &
getBoxMin()
const override {
return _towerBlock.getBoxMin(); }
938 [[nodiscard]]
const std::array<double, 3> &
getHaloBoxMin()
const {
return _towerBlock.getHaloBoxMin(); }
940 [[nodiscard]]
double getCutoff()
const override {
return _cutoff; }
942 void setCutoff(
double cutoff)
override { _cutoff = cutoff; }
950 void setSkin(
double skin) { this->_skin = skin; }
967 _isValid.store(ValidityState::invalid, std::memory_order::memory_order_relaxed);
968 std::for_each(_particlesToAdd.begin(), _particlesToAdd.end(), [](
auto &buffer) { buffer.clear(); });
969 std::for_each(_towerBlock.begin(), _towerBlock.end(), [](
auto &tower) { tower.clear(); });
977 return _neighborLists;
986 using namespace utils::ArrayMath::literals;
988 typename decltype(_particlesToAdd)::value_type particlesToAdd;
989 const size_t numParticlesToAdd =
990 std::accumulate(_particlesToAdd.begin(), _particlesToAdd.end(), 0,
991 [](
size_t acc,
const auto &buffer) { return acc + buffer.size(); });
992 particlesToAdd.reserve(numParticlesToAdd);
993 std::for_each(_particlesToAdd.begin(), _particlesToAdd.end(), [&](
auto &particlesBuffer) {
994 particlesToAdd.insert(particlesToAdd.end(), particlesBuffer.begin(), particlesBuffer.end());
995 particlesBuffer.clear();
998 const double interactionLength = _cutoff + this->_skin;
999 _builder = std::make_unique<internal::VerletClusterListsRebuilder<Particle_T>>(
1000 _towerBlock, particlesToAdd, _neighborLists, _clusterSize, interactionLength * interactionLength, newton3);
1002 _numClusters = _builder->rebuildTowersAndClusters();
1004 _isValid.store(ValidityState::cellsValidListsInvalid, std::memory_order::memory_order_relaxed);
1005 for (
auto &tower : _towerBlock) {
1006 tower.setParticleDeletionObserver(
this);
1015 template <
class LoopBody>
1017 for (
size_t x = 0; x < _towerBlock.getTowersPerDim()[0]; x++) {
1018 for (
size_t y = 0; y < _towerBlock.getTowersPerDim()[1]; y++) {
1019 auto &tower = _towerBlock.getTowerByIndex2D(x, y);
1020 for (
auto clusterIter = tower.getFirstOwnedCluster(); clusterIter < tower.getFirstTailHaloCluster();
1022 loopBody(*clusterIter);
1037 template <
class LoopBody>
1039 const auto towersPerDimX = _towerBlock.getTowersPerDim()[0];
1040 const auto towersPerDimY = _towerBlock.getTowersPerDim()[1];
1043 for (
size_t x = 0; x < towersPerDimX; x++) {
1044 for (
size_t y = 0; y < towersPerDimY; y++) {
1045 auto &tower = _towerBlock.getTowerByIndex2D(x, y);
1047 for (
auto clusterIter = tower.getFirstOwnedCluster(); clusterIter < tower.getFirstTailHaloCluster();
1049 loopBody(*clusterIter);
1061 size_t numClusterPairs = 0;
1062 this->
template traverseClusters<false>(
1063 [&numClusterPairs](
auto &cluster) { numClusterPairs += cluster.getNeighbors()->size(); });
1065 constexpr int minNumClusterPairsPerThread = 1000;
1069 size_t numClusterPairsPerThread =
1070 std::max(
static_cast<unsigned long>(std::ceil(
static_cast<double>(numClusterPairs) / numThreads)), 1ul);
1071 if (numClusterPairsPerThread * numThreads < numClusterPairs) {
1073 "VerletClusterLists::calculateClusterThreadPartition(): numClusterPairsPerThread ({}) * numThreads ({})={} "
1075 "be at least the amount of Cluster Pairs ({})!",
1076 numClusterPairsPerThread, numThreads, numClusterPairsPerThread * numThreads, numClusterPairs);
1078 fillClusterRanges(numClusterPairsPerThread, numThreads);
1088 if (numClusterPairsPerThread < 1) {
1090 "VerletClusterLists::fillClusterRanges(): numClusterPairsPerThread({}) is less than one, this is not "
1092 "and will lead to errors!",
1093 numClusterPairsPerThread);
1095 _clusterThreadPartition.resize(numThreads);
1097 size_t currentThread = 0;
1098 size_t currentNumClustersToAdd = 0;
1099 size_t numClusterPairsTotal = 0;
1100 bool threadIsInitialized =
false;
1102 for (
size_t currentTowerIndex = 0; currentTowerIndex < _towerBlock.size(); currentTowerIndex++) {
1103 auto ¤tTower = _towerBlock[currentTowerIndex];
1104 const auto firstOwnedClusterIndex =
1105 std::distance(currentTower.getClusters().begin(), currentTower.getFirstOwnedCluster());
1106 const auto firstTailHaloClusterIndex =
1107 std::distance(currentTower.getClusters().begin(), currentTower.getFirstTailHaloCluster());
1108 for (
size_t currentClusterInTower = firstOwnedClusterIndex; currentClusterInTower < firstTailHaloClusterIndex;
1109 ++currentClusterInTower) {
1110 auto ¤tCluster = currentTower.getCluster(currentClusterInTower);
1113 if (not threadIsInitialized) {
1114 _clusterThreadPartition[currentThread] = {currentTowerIndex, currentClusterInTower, 0};
1115 threadIsInitialized =
true;
1118 currentNumClustersToAdd++;
1119 numClusterPairsTotal += currentCluster.getNeighbors()->size();
1122 if (numClusterPairsTotal >= numClusterPairsPerThread * (currentThread + 1)) {
1124 _clusterThreadPartition[currentThread].numClusters += currentNumClustersToAdd;
1125 currentNumClustersToAdd = 0;
1130 if (currentThread >= numThreads) {
1132 threadIsInitialized =
true;
1134 threadIsInitialized =
false;
1139 if (not threadIsInitialized) {
1140 _clusterThreadPartition[currentThread] = {0, 0, 0};
1143 if (currentNumClustersToAdd != 0) {
1144 _clusterThreadPartition[currentThread].numClusters += currentNumClustersToAdd;
1147 while (++currentThread < numThreads) {
1148 _clusterThreadPartition[currentThread] = {0, 0, 0};
1159 _isValid.store(ValidityState::invalid, std::memory_order::memory_order_relaxed);
1177 template <
bool regionIter>
1178 [[nodiscard]] std::tuple<size_t, size_t> advanceIteratorIndices(
1179 size_t cellIndex,
size_t particleIndex, IteratorBehavior iteratorBehavior,
const std::array<double, 3> &boxMin,
1180 const std::array<double, 3> &boxMax,
const std::array<double, 3> &boxMinWithSafetyMargin,
1181 const std::array<double, 3> &boxMaxWithSafetyMargin,
size_t endCellIndex)
const {
1186 auto towerIsRelevant = [&]() ->
bool {
1188 if (_towerBlock.size() == 1) {
1191 bool isRelevant =
true;
1192 if constexpr (regionIter) {
1194 const auto [towerLowCorner, towerHighCorner] = _towerBlock.getTowerBoundingBox(cellIndex);
1196 utils::boxesOverlap(towerLowCorner, towerHighCorner, boxMinWithSafetyMargin, boxMaxWithSafetyMargin);
1207 while (not towerIsRelevant() or particleIndex >= _towerBlock[cellIndex].getNumActualParticles()) {
1208 cellIndex += stride;
1213 if (cellIndex > endCellIndex) {
1214 return {std::numeric_limits<size_t>::max(), particleIndex};
1217 }
while (not containerIteratorUtils::particleFulfillsIteratorRequirements<regionIter>(
1218 _towerBlock[cellIndex][particleIndex], iteratorBehavior, boxMin, boxMax));
1221 return {cellIndex, particleIndex};
1234 size_t _clusterSize;
1239 size_t _numClusters{0};
1246 mutable std::vector<std::vector<Particle_T>> _particlesToAdd;
1253 [[nodiscard]]
bool particlesToAddEmpty(
int bufferID = -1)
const {
1254 if (bufferID == -1) {
1255 for (
auto &threadBuffer : _particlesToAdd) {
1256 if (not threadBuffer.empty()) {
1262 return _particlesToAdd[bufferID].empty();
1274 template <
class VecVec>
1275 void appendBuffersHelper(VecVec *additionalVectors, VecVec &outVec)
const {
1276 if (additionalVectors) {
1277 outVec.reserve(_particlesToAdd.size() + additionalVectors->size());
1278 outVec.insert(outVec.end(), additionalVectors->begin(), additionalVectors->end());
1280 outVec.reserve(_particlesToAdd.size());
1282 for (
auto &vec : _particlesToAdd) {
1283 outVec.push_back(&vec);
1290 std::vector<ClusterRange> _clusterThreadPartition;
1300 unsigned int _rebuildFrequency{};
1304 enum class ValidityState :
unsigned char {
1306 cellsValidListsInvalid = 1,
1307 cellsAndListsValid = 2
1313 std::atomic<ValidityState> _isValid{ValidityState::invalid};
1318 std::unique_ptr<internal::VerletClusterListsRebuilder<Particle_T>> _builder;
#define AUTOPAS_OPENMP(args)
Empty macro to throw away any arguments.
Definition: WrapOpenMP.h:126
Base class for traversals utilising load balancing.
Definition: BalancedTraversal.h:19
std::function< unsigned long(const std::array< unsigned long, 3 > &, const std::array< unsigned long, 3 > &, const std::array< unsigned long, 3 > &)> EstimatorFunction
Type signature for load estimators.
Definition: BalancedTraversal.h:26
Public iterator class that iterates over a particle container and additional vectors (which are typic...
Definition: ContainerIterator.h:93
std::conditional_t< modifiable, std::vector< std::vector< Particle_T > * >, std::vector< std::vector< Particle_T > const * > > ParticleVecType
Type of the additional vector collection.
Definition: ContainerIterator.h:106
Functor base class.
Definition: Functor.h:40
Class representing the load estimator choices.
Definition: LoadEstimatorOption.h:18
Value
Possible choices for the load estimation algorithm.
Definition: LoadEstimatorOption.h:23
@ neighborListLength
Sum of neighbor list lengths.
Definition: LoadEstimatorOption.h:35
@ none
No load estimator.
Definition: LoadEstimatorOption.h:27
Class for manual memory management of neighbor lists.
Definition: NeighborListsBuffer.h:31
The ParticleContainerInterface class provides a basic interface for all Containers within AutoPas.
Definition: ParticleContainerInterface.h:37
This interface serves as a common parent class for all traversals.
Definition: TraversalInterface.h:18
virtual void endTraversal()=0
Finalizes the traversal.
virtual TraversalOption getTraversalType() const =0
Return a enum representing the name of the traversal class.
virtual void traverseParticles()=0
Traverse the particles by pairs, triplets etc.
virtual void initTraversal()=0
Initializes the traversal.
bool getUseNewton3() const
Return whether the traversal uses newton 3.
Definition: TraversalInterface.h:63
Info for traversals of a specific container.
Definition: TraversalSelectorInfo.h:14
Interface for traversals of the VerletClusterLists container.
Definition: VCLTraversalInterface.h:20
virtual void setClusterLists(VerletClusterLists< Particle_T > &verletClusterLists)
Sets the cluster list for the traversal to iterate over.
Definition: VCLTraversalInterface.h:31
Particles are divided into clusters.
Definition: VerletClusterLists.h:56
TraversalSelectorInfo getTraversalSelectorInfo() const override
Generates a traversal selector info for this container.
Definition: VerletClusterLists.h:389
void reduce(Lambda reduceLambda, A &result, IteratorBehavior behavior=autopas::IteratorBehavior::ownedOrHalo)
Reduce properties of particles as defined by a lambda function.
Definition: VerletClusterLists.h:510
ContainerOption getContainerType() const override
Get the ContainerType.
Definition: VerletClusterLists.h:105
void traverseClusters(LoopBody &&loopBody)
Helper method to iterate over all clusters.
Definition: VerletClusterLists.h:797
void deleteHaloParticles() override
Deletes all halo particles.
Definition: VerletClusterLists.h:211
void forEach(Lambda forEachLambda, IteratorBehavior behavior=autopas::IteratorBehavior::ownedOrHalo) const
Execute code on all particles in this container as defined by a lambda function.
Definition: VerletClusterLists.h:480
size_t size() const override
Get the number of all particles stored in this container (owned + halo + dummy).
Definition: VerletClusterLists.h:809
auto getClusterSize() const
Returns the number of particles in each cluster.
Definition: VerletClusterLists.h:867
void rebuildNeighborLists(TraversalInterface *traversal) override
Rebuilds the neighbor lists for the next traversals.
Definition: VerletClusterLists.h:767
CellType getParticleCellTypeEnum() const override
Get the ParticleCell type as an Enum.
Definition: VerletClusterLists.h:103
BalancedTraversal::EstimatorFunction getLoadEstimatorFunction()
Generates the load estimation function depending on _loadEstimator.
Definition: VerletClusterLists.h:111
void setSkin(double skin)
Set the verlet skin length for the container.
Definition: VerletClusterLists.h:950
void addHaloParticleImpl(const Particle_T &haloParticle) override
Adds a particle to the container that lies in the halo region of the container.
Definition: VerletClusterLists.h:186
auto getTowersPerDimension() const
Returns the number of grids per dimension on the container.
Definition: VerletClusterLists.h:861
void forEach(Lambda forEachLambda, IteratorBehavior behavior=autopas::IteratorBehavior::ownedOrHalo)
Execute code on all particles in this container as defined by a lambda function.
Definition: VerletClusterLists.h:461
const std::array< double, 3 > & getHaloBoxMax() const
Get the upper corner of the halo box.
Definition: VerletClusterLists.h:930
std::tuple< const Particle_T *, size_t, size_t > getParticleImpl(size_t cellIndex, size_t particleIndex, IteratorBehavior iteratorBehavior, const std::array< double, 3 > &boxMin, const std::array< double, 3 > &boxMax) const
Container specific implementation for getParticle.
Definition: VerletClusterLists.h:283
void addParticleImpl(const Particle_T &p) override
Adds the given particle to the container.
Definition: VerletClusterLists.h:181
void reduceInRegion(Lambda reduceLambda, A &result, const std::array< double, 3 > &lowerCorner, const std::array< double, 3 > &higherCorner, IteratorBehavior behavior=autopas::IteratorBehavior::ownedOrHalo)
Execute code on all particles in this container in a certain region as defined by a lambda function.
Definition: VerletClusterLists.h:695
void traverseClustersSequential(LoopBody &&loopBody)
Helper method to sequentially iterate over all owned clusters.
Definition: VerletClusterLists.h:1016
ContainerIterator< Particle_T, false, true > getRegionIterator(const std::array< double, 3 > &lowerCorner, const std::array< double, 3 > &higherCorner, IteratorBehavior behavior, typename ContainerIterator< Particle_T, false, true >::ParticleVecType *additionalVectors=nullptr) const override
Iterate over all particles in a specified region for(auto iter = container.getRegionIterator(lowCorne...
Definition: VerletClusterLists.h:587
void computeInteractions(TraversalInterface *traversal) override
Iterates over all particle multiples (e.g.
Definition: VerletClusterLists.h:144
double getInteractionLength() const override
Return the interaction length (cutoff+skin) of the container.
Definition: VerletClusterLists.h:964
bool deleteParticle(size_t cellIndex, size_t particleIndex) override
Deletes the particle at the given index positions as long as this does not compromise the validity of...
Definition: VerletClusterLists.h:353
double getVerletSkin() const override
Return the verletSkin of the container verletSkin.
Definition: VerletClusterLists.h:944
void loadParticlesIntoSoAs(Functor *functor)
Loads all particles of the container in their correct SoA and generates the SoAViews for the clusters...
Definition: VerletClusterLists.h:881
std::tuple< const Particle_T *, size_t, size_t > getParticle(size_t cellIndex, size_t particleIndex, IteratorBehavior iteratorBehavior, const std::array< double, 3 > &boxMin, const std::array< double, 3 > &boxMax) const override
Fetch the pointer to a particle, identified via a cell and particle index.
Definition: VerletClusterLists.h:254
void setRebuildFrequency(unsigned int rebuildFrequency)
Set the rebuild Frequency value for the container.
Definition: VerletClusterLists.h:962
internal::ClusterTowerBlock2D< Particle_T > & getTowerBlock()
Getter for the cell block.
Definition: VerletClusterLists.h:922
auto getNumTowersPerInteractionLength() const
Returns the towers per interaction length.
Definition: VerletClusterLists.h:873
const std::array< double, 3 > & getBoxMin() const override
Get the lower corner of the container without halo.
Definition: VerletClusterLists.h:932
void deleteAllParticles() override
Deletes all particles.
Definition: VerletClusterLists.h:966
void fillClusterRanges(size_t numClusterPairsPerThread, int numThreads)
Fills in the cluster ranges of the cluster thread partition.
Definition: VerletClusterLists.h:1087
ContainerIterator< Particle_T, true, true > getRegionIterator(const std::array< double, 3 > &lowerCorner, const std::array< double, 3 > &higherCorner, IteratorBehavior behavior, typename ContainerIterator< Particle_T, true, true >::ParticleVecType *additionalVectors=nullptr) override
Iterate over all particles in a specified region for(auto iter = container.getRegionIterator(lowCorne...
Definition: VerletClusterLists.h:558
ContainerIterator< Particle_T, true, false > begin(IteratorBehavior behavior=autopas::IteratorBehavior::ownedOrHalo, typename ContainerIterator< Particle_T, true, false >::ParticleVecType *additionalVectors=nullptr) override
Iterate over all particles using for(auto iter = container.begin(); iter.isValid(); ++iter) .
Definition: VerletClusterLists.h:404
VerletClusterLists(const std::array< double, 3 > &boxMin, const std::array< double, 3 > &boxMax, double cutoff, double skin, unsigned int rebuildFrequency, size_t clusterSize, LoadEstimatorOption loadEstimator=LoadEstimatorOption::none)
Constructor of the VerletClusterLists class.
Definition: VerletClusterLists.h:89
void reduce(Lambda reduceLambda, A &result, IteratorBehavior behavior=autopas::IteratorBehavior::ownedOrHalo) const
Reduce properties of particles as defined by a lambda function.
Definition: VerletClusterLists.h:529
size_t getNumberOfParticles(IteratorBehavior behavior) const override
Get the number of particles with respect to the specified IteratorBehavior.
Definition: VerletClusterLists.h:820
ContainerIterator< Particle_T, false, false > begin(IteratorBehavior behavior=autopas::IteratorBehavior::ownedOrHalo, typename ContainerIterator< Particle_T, false, false >::ParticleVecType *additionalVectors=nullptr) const override
Iterate over all particles using for(auto iter = container.begin(); iter.isValid(); ++iter) .
Definition: VerletClusterLists.h:432
void forEachInRegion(Lambda forEachLambda, const std::array< double, 3 > &lowerCorner, const std::array< double, 3 > &higherCorner, IteratorBehavior behavior=autopas::IteratorBehavior::ownedOrHalo) const
Execute code on all particles in this container in a certain region as defined by a lambda function.
Definition: VerletClusterLists.h:651
unsigned int getRebuildFrequency()
Get the rebuild Frequency value for the container.
Definition: VerletClusterLists.h:956
void traverseClustersParallel(LoopBody &&loopBody)
Helper method to iterate over all clusters in parallel.
Definition: VerletClusterLists.h:1038
const std::array< double, 3 > & getHaloBoxMin() const
Get the lower corner of the halo box.
Definition: VerletClusterLists.h:938
const internal::VerletClusterListsRebuilder< Particle_T >::NeighborListsBuffer_T & getNeighborLists() const
Get the neighbor lists buffer object.
Definition: VerletClusterLists.h:976
double getCutoff() const override
Return the cutoff of the container.
Definition: VerletClusterLists.h:940
internal::ClusterTower< Particle_T > & getTowerByIndex(size_t x, size_t y)
Returns a reference to the tower for the given tower grid coordinates.
Definition: VerletClusterLists.h:911
auto getTowerSideLength() const
Returns the grid side length of the grids in the container.
Definition: VerletClusterLists.h:855
void reduceInRegion(Lambda reduceLambda, A &result, const std::array< double, 3 > &lowerCorner, const std::array< double, 3 > &higherCorner, IteratorBehavior behavior=autopas::IteratorBehavior::ownedOrHalo) const
Execute code on all particles in this container in a certain region as defined by a lambda function.
Definition: VerletClusterLists.h:728
const std::array< double, 3 > & getBoxMax() const override
Get the upper corner of the container without halo.
Definition: VerletClusterLists.h:924
void reserve(size_t numParticles, size_t numParticlesHaloEstimate) override
Reserve memory for a given number of particles in the container and logic layers.
Definition: VerletClusterLists.h:169
void setCutoff(double cutoff) override
Set the cutoff of the container.
Definition: VerletClusterLists.h:942
bool deleteParticle(Particle_T &particle) override
Deletes the given particle as long as this does not compromise the validity of the container.
Definition: VerletClusterLists.h:347
std::tuple< const Particle_T *, size_t, size_t > getParticle(size_t cellIndex, size_t particleIndex, IteratorBehavior iteratorBehavior) const override
Fetch the pointer to a particle, identified via a cell and particle index.
Definition: VerletClusterLists.h:260
auto getNumClusters() const
Returns the number of clusters in this container.
Definition: VerletClusterLists.h:849
std::vector< Particle_T > updateContainer(bool keepNeighborListsValid) override
Updates the container.
Definition: VerletClusterLists.h:359
void rebuildTowersAndClusters(bool newton3)
Initializes a new VerletClusterListsRebuilder and uses it to rebuild the towers and the clusters.
Definition: VerletClusterLists.h:985
void calculateClusterThreadPartition()
Calculates a cluster thread partition that aims to give each thread about the same amount of cluster ...
Definition: VerletClusterLists.h:1060
void extractParticlesFromSoAs(Functor *functor)
Extracts all SoAs of the container into the particles.
Definition: VerletClusterLists.h:896
void forEachInRegion(Lambda forEachLambda, const std::array< double, 3 > &lowerCorner, const std::array< double, 3 > &higherCorner, IteratorBehavior behavior=autopas::IteratorBehavior::ownedOrHalo)
Execute code on all particles in this container in a certain region as defined by a lambda function.
Definition: VerletClusterLists.h:618
bool updateHaloParticle(const Particle_T &haloParticle) override
Update a halo particle of the container with the given haloParticle.
Definition: VerletClusterLists.h:191
void notifyParticleDeleted() override
If a particle is deleted, we want _isValid to be set to invalid, as the tower structure is invalidate...
Definition: VerletClusterLists.h:1157
const auto & getClusterThreadPartition() const
Returns the cluster-thread-partition.
Definition: VerletClusterLists.h:843
Class to manage the grid of towers for the Verlet Cluster Lists container.
Definition: ClusterTowerBlock2D.h:25
This class represents one tower for clusters in the VerletClusterLists container.
Definition: ClusterTower.h:43
Class that is notified when a particle is deleted.
Definition: ParticleDeletedObserver.h:15
static void exception(const Exception e)
Handle an exception derived by std::exception.
Definition: ExceptionHandler.h:63
std::vector< typename ContainerType::ParticleType > collectParticlesAndMarkNonOwnedAsDummy(ContainerType &container)
Collects leaving particles and marks halo particles as dummy.
Definition: LeavingParticleCollector.h:85
void markParticleAsDeleted(Particle_T &p)
Marks a particle as deleted.
Definition: markParticleAsDeleted.h:23
void deleteParticle(ParticleIterator &iterator)
Function to access private iterator.deleteCurrentParticle() via friend.
Definition: ContainerIterator.h:35
constexpr std::array< T, SIZE > subScalar(const std::array< T, SIZE > &a, T s)
Subtracts a scalar s from each element of array a and returns the result.
Definition: ArrayMath.h:164
constexpr std::array< T, SIZE > addScalar(const std::array< T, SIZE > &a, T s)
Adds a scalar s to each element of array a and returns the result.
Definition: ArrayMath.h:147
bool boxesOverlap(const std::array< T, 3 > &boxALow, const std::array< T, 3 > &boxAHigh, const std::array< T, 3 > &boxBLow, const std::array< T, 3 > &boxBHigh)
Checks if two boxes have overlap.
Definition: inBox.h:67
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
CellType
The ParticleCell Type as an Enum.
Definition: ParticleCell.h:19
@ ClusterTower
ClusterTower : Tower for the 2D tower structure of VerletClusterLists.
int autopas_get_num_threads()
Dummy for omp_get_num_threads() when no OpenMP is available.
Definition: WrapOpenMP.h:138
int autopas_get_max_threads()
Dummy for omp_get_max_threads() when no OpenMP is available.
Definition: WrapOpenMP.h:144
int autopas_get_thread_num()
Dummy for omp_set_lock() when no OpenMP is available.
Definition: WrapOpenMP.h:132
Defines a cluster range used in the static cluster-thread-partition.
Definition: VerletClusterLists.h:61
size_t startIndexInTower
The index of the first cluster in its tower.
Definition: VerletClusterLists.h:69
size_t startTowerIndex
The index of the tower that contains the first cluster.
Definition: VerletClusterLists.h:65
size_t numClusters
The number of clusters in the range.
Definition: VerletClusterLists.h:73