55template <
class Particle_T>
97 VerletClusterLists(
const std::array<double, 3> &boxMin,
const std::array<double, 3> &boxMax,
double cutoff,
100 _towerBlock{boxMin, boxMax, cutoff + skin},
101 _clusterSize{clusterSize},
104 _loadEstimator(loadEstimator) {
106 _towerBlock.addTower(_clusterSize);
109 [[nodiscard]] ContainerOption
getContainerType()
const override {
return ContainerOption::verletClusterLists; }
119 return [&](
const std::array<unsigned long, 3> &cellsPerDimension,
120 const std::array<unsigned long, 3> &lowerCorner,
const std::array<unsigned long, 3> &upperCorner) {
122 unsigned long sum = 0;
123 for (
unsigned long x = lowerCorner[0]; x <= upperCorner[0]; x++) {
124 for (
unsigned long y = lowerCorner[1]; y <= upperCorner[1]; y++) {
125 unsigned long cellLoad = 0;
126 auto &tower = _towerBlock.getTowerByIndex2D(x, y);
127 for (
auto &cluster : tower.getClusters()) {
128 if (cluster.getNeighbors()) {
129 cellLoad += cluster.getNeighbors()->size();
142 [&](
const std::array<unsigned long, 3> &cellsPerDimension,
const std::array<unsigned long, 3> &lowerCorner,
143 const std::array<unsigned long, 3> &upperCorner) {
return 1; };
149 if (_isValid == ValidityState::cellsAndListsValid) {
151 "VerletClusterLists::computeInteractions(): Trying to do a pairwise iteration, even though verlet lists are "
155 if (traversalInterface) {
157 traversalInterface->setTowers(_towerBlock.getTowersRef());
160 "Trying to use a traversal of wrong type in VerletClusterLists::computeInteractions. TraversalID: {}",
172 void reserve(
size_t numParticles,
size_t numParticlesHaloEstimate)
override {
173 const auto particlesPerTower = (numParticles + numParticlesHaloEstimate) / _towerBlock.size();
174 for (
auto &tower : _towerBlock) {
175 tower.reserve(particlesPerTower);
185 _isValid.store(ValidityState::invalid, std::memory_order_relaxed);
190 _isValid.store(ValidityState::invalid, std::memory_order_relaxed);
195 using namespace autopas::utils::ArrayMath::literals;
197 const auto &haloPos = haloParticle.getR();
200 IteratorBehavior::halo | IteratorBehavior::forceSequential,
nullptr);
201 it.isValid(); ++it) {
202 if (haloParticle.getID() == it->getID()) {
206 it->setV(haloParticle.getV());
207 it->setF(haloParticle.getF());
216 for (
auto &particleVec : _particlesToAdd) {
217 for (
size_t j = 0; j < particleVec.size();) {
218 if (particleVec[j].isHalo()) {
219 particleVec[j] = particleVec[particleVec.size() - 1];
220 particleVec.pop_back();
227 bool deletedSomething =
false;
230 for (
size_t i = 0; i < _towerBlock.size(); ++i) {
231 auto &tower = _towerBlock[i];
232 const auto towerSize = tower.size();
233 auto numTailDummies = tower.getNumTailDummyParticles();
235 for (
size_t j = 0; numTailDummies < towerSize and j < towerSize - numTailDummies;) {
236 if (tower[j].isHalo()) {
238 tower[j] = tower[towerSize - 1 - numTailDummies];
242 deletedSomething =
true;
248 if (deletedSomething) {
249 tower.deleteDummyParticles();
252 if (deletedSomething) {
253 _isValid.store(ValidityState::invalid, std::memory_order_relaxed);
257 std::tuple<const Particle_T *, size_t, size_t>
getParticle(
size_t cellIndex,
size_t particleIndex,
258 IteratorBehavior iteratorBehavior,
259 const std::array<double, 3> &boxMin,
260 const std::array<double, 3> &boxMax)
const override {
261 return getParticleImpl<true>(cellIndex, particleIndex, iteratorBehavior, boxMin, boxMax);
263 std::tuple<const Particle_T *, size_t, size_t>
getParticle(
size_t cellIndex,
size_t particleIndex,
264 IteratorBehavior iteratorBehavior)
const override {
266 constexpr std::array<double, 3> boxMin{std::numeric_limits<double>::lowest(), std::numeric_limits<double>::lowest(),
267 std::numeric_limits<double>::lowest()};
269 constexpr std::array<double, 3> boxMax{std::numeric_limits<double>::max(), std::numeric_limits<double>::max(),
270 std::numeric_limits<double>::max()};
271 return getParticleImpl<false>(cellIndex, particleIndex, iteratorBehavior, boxMin, boxMax);
285 template <
bool regionIter>
286 std::tuple<const Particle_T *, size_t, size_t>
getParticleImpl(
size_t cellIndex,
size_t particleIndex,
287 IteratorBehavior iteratorBehavior,
288 const std::array<double, 3> &boxMin,
289 const std::array<double, 3> &boxMax)
const {
290 using namespace autopas::utils::ArrayMath::literals;
294 if (_towerBlock.empty()) {
295 return {
nullptr, 0, 0};
298 std::array<double, 3> boxMinWithSafetyMargin = boxMin;
299 std::array<double, 3> boxMaxWithSafetyMargin = boxMax;
300 if constexpr (regionIter) {
307 const auto [startCellIndex, endCellIndex] = [&]() -> std::tuple<size_t, size_t> {
308 if constexpr (regionIter) {
310 return {_towerBlock.getTowerIndex1DAtPosition(boxMinWithSafetyMargin),
311 _towerBlock.getTowerIndex1DAtPosition(boxMaxWithSafetyMargin)};
313 if (not(iteratorBehavior & IteratorBehavior::halo)) {
315 return {_towerBlock.getFirstOwnedTowerIndex(), _towerBlock.getLastOwnedTowerIndex()};
318 return {0, _towerBlock.size() - 1};
324 if (cellIndex == 0 and particleIndex == 0) {
329 if (cellIndex >= _towerBlock.size()) {
330 return {
nullptr, 0, 0};
333 if (particleIndex >= _towerBlock[cellIndex].getNumActualParticles() or
334 not containerIteratorUtils::particleFulfillsIteratorRequirements<regionIter>(
335 _towerBlock[cellIndex][particleIndex], iteratorBehavior, boxMin, boxMax)) {
337 std::tie(cellIndex, particleIndex) =
338 advanceIteratorIndices<regionIter>(cellIndex, particleIndex, iteratorBehavior, boxMin, boxMax,
339 boxMinWithSafetyMargin, boxMaxWithSafetyMargin, endCellIndex);
342 if (cellIndex > endCellIndex) {
343 return {
nullptr, 0, 0};
345 const Particle_T *retPtr = &_towerBlock[cellIndex][particleIndex];
347 return {retPtr, cellIndex, particleIndex};
362 [[nodiscard]] std::vector<Particle_T>
updateContainer(
bool keepNeighborListsValid)
override {
363 if (keepNeighborListsValid) {
370 for (
size_t i = 0ul; i < _towerBlock.size(); ++i) {
371 _towerBlock[i].deleteDummyParticles();
375 for (
size_t i = 0ul; i < _particlesToAdd.size(); ++i) {
376 _particlesToAdd[i].erase(std::remove_if(_particlesToAdd[i].
begin(), _particlesToAdd[i].
end(),
377 [](
const auto &p) {
return p.isDummy(); }),
378 _particlesToAdd[i].
end());
382 std::vector<Particle_T> invalidParticles;
386 vecMergeParticle : std::vector<Particle_T> : omp_out.insert(omp_out.end(), omp_in.begin(), omp_in.end())))
387 AUTOPAS_OPENMP(parallel reduction(vecMergeParticle : invalidParticles)) {
388 for (
auto iter = this->
begin(IteratorBehavior::owned); iter.isValid(); ++iter) {
390 invalidParticles.push_back(*iter);
395 _isValid.store(ValidityState::invalid, std::memory_order_relaxed);
396 return invalidParticles;
400 using namespace autopas::utils::ArrayMath::literals;
403 const auto [towerSideLength, towersPerDim] = _towerBlock.estimateOptimalGridSideLength(
405 const std::array<double, 3> towerSize = {towerSideLength[0], towerSideLength[1],
407 const std::array<unsigned long, 3> towerDimensions = {towersPerDim[0], towersPerDim[1], 1};
415 IteratorBehavior behavior = IteratorBehavior::ownedOrHalo,
419 if (_isValid != ValidityState::invalid) {
424 "VerletClusterLists::begin(): Error: particle container is valid, but _particlesToAdd isn't empty!");
433 appendBuffersHelper(additionalVectors, additionalVectorsToPass);
443 IteratorBehavior behavior = autopas::IteratorBehavior::ownedOrHalo,
445 nullptr)
const override {
448 if (_isValid != ValidityState::invalid) {
453 "VerletClusterLists::begin() const: Error: particle container is valid, but _particlesToAdd isn't empty!");
462 appendBuffersHelper(additionalVectors, additionalVectorsToPass);
470 template <
typename Lambda>
471 void forEach(Lambda forEachLambda, IteratorBehavior behavior = autopas::IteratorBehavior::ownedOrHalo) {
472 for (
auto &tower : _towerBlock) {
473 tower.forEach(forEachLambda, behavior);
475 for (
auto &vector : this->_particlesToAdd) {
476 for (
auto &particle : vector) {
477 if (behavior.contains(particle)) {
478 forEachLambda(particle);
489 template <
typename Lambda>
490 void forEach(Lambda forEachLambda, IteratorBehavior behavior = autopas::IteratorBehavior::ownedOrHalo)
const {
491 if (_isValid != ValidityState::invalid) {
492 if (not particlesToAddEmpty()) {
494 "VerletClusterLists::forEach() const: Error: particle container is valid, but _particlesToAdd isn't "
500 for (
auto &tower : _towerBlock) {
501 tower.forEach(forEachLambda, behavior);
505 if (_isValid == ValidityState::invalid) {
506 for (
auto &particlesToAddPerThread : _particlesToAdd) {
507 for (
auto &particle : particlesToAddPerThread) {
508 if (behavior.contains(particle)) {
509 forEachLambda(particle);
519 template <
typename Lambda,
typename A>
520 void reduce(Lambda reduceLambda, A &result, IteratorBehavior behavior = autopas::IteratorBehavior::ownedOrHalo) {
521 for (
auto &tower : _towerBlock) {
522 tower.reduce(reduceLambda, result, behavior);
524 for (
auto &vector : this->_particlesToAdd) {
525 for (
auto &p : vector) {
526 if (behavior.contains(p)) {
527 reduceLambda(p, result);
538 template <
typename Lambda,
typename A>
539 void reduce(Lambda reduceLambda, A &result,
540 IteratorBehavior behavior = autopas::IteratorBehavior::ownedOrHalo)
const {
541 if (_isValid != ValidityState::invalid) {
542 if (not particlesToAddEmpty()) {
544 "VerletClusterLists::reduce() const: Error: particle container is valid, but _particlesToAdd isn't empty!");
549 for (
auto tower : _towerBlock) {
550 tower.reduce(reduceLambda, result, behavior);
553 if (_isValid == ValidityState::invalid) {
555 for (
auto &particlesToAddPerThread : _particlesToAdd) {
556 for (
auto &particle : particlesToAddPerThread) {
557 if (behavior.contains(particle)) {
558 reduceLambda(particle, result);
569 const std::array<double, 3> &lowerCorner,
const std::array<double, 3> &higherCorner, IteratorBehavior behavior,
573 if (_isValid != ValidityState::invalid) {
578 "VerletClusterLists::reduce() const: Error: particle container is valid, but _particlesToAdd isn't empty!");
587 appendBuffersHelper(additionalVectors, additionalVectorsToPass);
598 const std::array<double, 3> &lowerCorner,
const std::array<double, 3> &higherCorner, IteratorBehavior behavior,
600 nullptr)
const override {
603 if (_isValid != ValidityState::invalid) {
608 "VerletClusterLists::getRegionIterator() const: Error: particle container is valid, but _particlesToAdd "
618 appendBuffersHelper(additionalVectors, additionalVectorsToPass);
627 template <
typename Lambda>
629 const std::array<double, 3> &higherCorner,
630 IteratorBehavior behavior = autopas::IteratorBehavior::ownedOrHalo) {
631 for (
size_t i = 0; i < _towerBlock.size(); ++i) {
632 if (_towerBlock.ignoreCellForIteration(i, behavior)) {
635 auto &tower = _towerBlock[i];
636 const auto [towerLowCorner, towerHighCorner] = _towerBlock.getTowerBoundingBox(i);
640 if (
utils::boxesOverlap(towerLowCornerSkin, towerHighCornerSkin, lowerCorner, higherCorner)) {
641 tower.forEach(forEachLambda, lowerCorner, higherCorner, behavior);
644 for (
auto &vector : _particlesToAdd) {
645 for (
auto &particle : vector) {
646 if (behavior.contains(particle)) {
647 if (
utils::inBox(particle.getR(), lowerCorner, higherCorner)) {
648 forEachLambda(particle);
660 template <
typename Lambda>
662 const std::array<double, 3> &higherCorner,
663 IteratorBehavior behavior = autopas::IteratorBehavior::ownedOrHalo)
const {
664 if (_isValid != ValidityState::invalid) {
665 if (not particlesToAddEmpty()) {
667 "VerletClusterLists::forEachInRegion() const: Error: particle container is valid, but _particlesToAdd "
673 for (
size_t i = 0; i < _towerBlock.size(); ++i) {
674 if (_towerBlock.ignoreCellForIteration(i, behavior)) {
677 auto &tower = _towerBlock[i];
678 const auto [towerLowCorner, towerHighCorner] = _towerBlock.getTowerBoundingBox(i);
682 if (
utils::boxesOverlap(towerLowCornerSkin, towerHighCornerSkin, lowerCorner, higherCorner)) {
683 tower.forEach(forEachLambda, lowerCorner, higherCorner, behavior);
687 if (_isValid == ValidityState::invalid) {
689 for (
auto &particlesToAddPerThread : _particlesToAdd) {
690 for (
auto &particle : particlesToAddPerThread) {
691 if (behavior.contains(particle)) {
692 if (
utils::inBox(particle.getR(), lowerCorner, higherCorner)) {
693 forEachLambda(particle);
704 template <
typename Lambda,
typename A>
705 void reduceInRegion(Lambda reduceLambda, A &result,
const std::array<double, 3> &lowerCorner,
706 const std::array<double, 3> &higherCorner,
707 IteratorBehavior behavior = autopas::IteratorBehavior::ownedOrHalo) {
708 for (
size_t i = 0; i < _towerBlock.size(); ++i) {
709 if (_towerBlock.ignoreCellForIteration(i, behavior)) {
712 auto &tower = _towerBlock[i];
713 const auto [towerLowCorner, towerHighCorner] = _towerBlock.getTowerBoundingBox(i);
717 if (
utils::boxesOverlap(towerLowCornerSkin, towerHighCornerSkin, lowerCorner, higherCorner)) {
718 tower.reduce(reduceLambda, result, lowerCorner, higherCorner, behavior);
721 for (
auto &vector : _particlesToAdd) {
722 for (
auto &particle : vector) {
723 if (behavior.contains(particle)) {
724 if (
utils::inBox(particle.getR(), lowerCorner, higherCorner)) {
725 reduceLambda(particle, result);
737 template <
typename Lambda,
typename A>
738 void reduceInRegion(Lambda reduceLambda, A &result,
const std::array<double, 3> &lowerCorner,
739 const std::array<double, 3> &higherCorner,
740 IteratorBehavior behavior = autopas::IteratorBehavior::ownedOrHalo)
const {
741 if (_isValid != ValidityState::invalid) {
742 if (not particlesToAddEmpty()) {
744 "VerletClusterLists::reduceInRegion() const: Error: particle container is valid, but _particlesToAdd isn't "
749 for (
size_t i = 0; i < _towerBlock.size(); ++i) {
750 if (_towerBlock.ignoreCellForIteration(i, behavior)) {
753 auto &tower = _towerBlock[i];
754 const auto [towerLowCorner, towerHighCorner] = _towerBlock.getTowerBoundingBox(i);
758 if (
utils::boxesOverlap(towerLowCornerSkin, towerHighCornerSkin, lowerCorner, higherCorner)) {
759 tower.reduce(reduceLambda, result, lowerCorner, higherCorner, behavior);
763 if (_isValid == ValidityState::invalid) {
765 for (
auto &particlesToAddPerThread : _particlesToAdd) {
766 for (
auto &particle : particlesToAddPerThread) {
767 if (behavior.contains(particle)) {
768 if (
utils::inBox(particle.getR(), lowerCorner, higherCorner)) {
769 reduceLambda(particle, result);
780 if (_isValid == ValidityState::invalid or traversal->
getUseNewton3() != _builder->getNewton3()) {
782 _neighborLists.clear();
785 _builder->rebuildNeighborListsAndFillClusters();
788 if (clusterTraversalInterface) {
789 if (clusterTraversalInterface->needsStaticClusterThreadPartition()) {
794 "Trying to use a traversal of wrong type in VerletClusterLists::rebuildNeighborLists. TraversalID: {}",
806 template <
bool inParallel,
class LoopBody>
809 traverseClustersParallel<LoopBody>(std::forward<LoopBody>(loopBody));
811 traverseClustersSequential<LoopBody>(std::forward<LoopBody>(loopBody));
819 [[nodiscard]]
size_t size()
const override {
820 size_t sum = std::accumulate(_towerBlock.begin(), _towerBlock.end(), 0,
821 [](
size_t acc,
const auto &tower) { return acc + tower.size(); });
822 sum = std::accumulate(_particlesToAdd.begin(), _particlesToAdd.end(), sum,
823 [](
size_t acc,
const auto &buffer) { return acc + buffer.size(); });
832 size_t sum = std::accumulate(_towerBlock.begin(), _towerBlock.end(), 0, [&behavior](
size_t acc,
const auto &tower) {
833 return acc + tower.getNumberOfParticles(behavior);
840 sum = std::accumulate(
841 _particlesToAdd.begin(), _particlesToAdd.end(), sum, [&behavior](
size_t acc,
const auto &buffer) {
843 (std::count_if(buffer.begin(), buffer.end(), [&behavior](auto p) { return behavior.contains(p); }));
890 template <
class Functor>
892 const auto numTowers = _towerBlock.size();
895 for (
size_t index = 0; index < numTowers; index++) {
896 _towerBlock[index].loadSoA(functor);
905 template <
class Functor>
907 const auto numTowers = _towerBlock.size();
910 for (
size_t index = 0; index < numTowers; index++) {
911 _towerBlock[index].extractSoA(functor);
922 return _towerBlock.getTowerByIndex2D(x, y);
934 [[nodiscard]]
const std::array<double, 3> &
getBoxMax()
const override {
return _towerBlock.getBoxMax(); }
940 [[nodiscard]]
const std::array<double, 3> &
getHaloBoxMax()
const {
return _towerBlock.getHaloBoxMax(); }
942 [[nodiscard]]
const std::array<double, 3> &
getBoxMin()
const override {
return _towerBlock.getBoxMin(); }
948 [[nodiscard]]
const std::array<double, 3> &
getHaloBoxMin()
const {
return _towerBlock.getHaloBoxMin(); }
950 [[nodiscard]]
double getCutoff()
const override {
return _cutoff; }
952 void setCutoff(
double cutoff)
override { _cutoff = cutoff; }
960 void setSkin(
double skin) { this->_skin = skin; }
965 _isValid.store(ValidityState::invalid, std::memory_order_relaxed);
966 std::for_each(_particlesToAdd.begin(), _particlesToAdd.end(), [](
auto &buffer) { buffer.clear(); });
967 std::for_each(_towerBlock.begin(), _towerBlock.end(), [](
auto &tower) { tower.clear(); });
975 return _neighborLists;
984 using namespace utils::ArrayMath::literals;
986 typename decltype(_particlesToAdd)::value_type particlesToAdd;
987 const size_t numParticlesToAdd =
988 std::accumulate(_particlesToAdd.begin(), _particlesToAdd.end(), 0,
989 [](
size_t acc,
const auto &buffer) { return acc + buffer.size(); });
990 particlesToAdd.reserve(numParticlesToAdd);
991 std::for_each(_particlesToAdd.begin(), _particlesToAdd.end(), [&](
auto &particlesBuffer) {
992 particlesToAdd.insert(particlesToAdd.end(), particlesBuffer.begin(), particlesBuffer.end());
993 particlesBuffer.clear();
996 const double interactionLength = _cutoff + this->_skin;
997 _builder = std::make_unique<internal::VerletClusterListsRebuilder<Particle_T>>(
998 _towerBlock, particlesToAdd, _neighborLists, _clusterSize, interactionLength * interactionLength, newton3);
1000 _numClusters = _builder->rebuildTowersAndClusters();
1002 _isValid.store(ValidityState::cellsValidListsInvalid, std::memory_order_relaxed);
1003 for (
auto &tower : _towerBlock) {
1004 tower.setParticleDeletionObserver(
this);
1013 template <
class LoopBody>
1015 for (
size_t x = 0; x < _towerBlock.getTowersPerDim()[0]; x++) {
1016 for (
size_t y = 0; y < _towerBlock.getTowersPerDim()[1]; y++) {
1017 auto &tower = _towerBlock.getTowerByIndex2D(x, y);
1018 for (
auto clusterIter = tower.getFirstOwnedCluster(); clusterIter < tower.getFirstTailHaloCluster();
1020 loopBody(*clusterIter);
1035 template <
class LoopBody>
1037 const auto towersPerDimX = _towerBlock.getTowersPerDim()[0];
1038 const auto towersPerDimY = _towerBlock.getTowersPerDim()[1];
1041 for (
size_t x = 0; x < towersPerDimX; x++) {
1042 for (
size_t y = 0; y < towersPerDimY; y++) {
1043 auto &tower = _towerBlock.getTowerByIndex2D(x, y);
1045 for (
auto clusterIter = tower.getFirstOwnedCluster(); clusterIter < tower.getFirstTailHaloCluster();
1047 loopBody(*clusterIter);
1059 size_t numClusterPairs = 0;
1060 this->
template traverseClusters<false>(
1061 [&numClusterPairs](
auto &cluster) { numClusterPairs += cluster.getNeighbors()->size(); });
1063 constexpr int minNumClusterPairsPerThread = 1000;
1067 size_t numClusterPairsPerThread =
1068 std::max(
static_cast<unsigned long>(std::ceil(
static_cast<double>(numClusterPairs) / numThreads)), 1ul);
1069 if (numClusterPairsPerThread * numThreads < numClusterPairs) {
1071 "VerletClusterLists::calculateClusterThreadPartition(): numClusterPairsPerThread ({}) * numThreads ({})={} "
1073 "be at least the amount of Cluster Pairs ({})!",
1074 numClusterPairsPerThread, numThreads, numClusterPairsPerThread * numThreads, numClusterPairs);
1076 fillClusterRanges(numClusterPairsPerThread, numThreads);
1086 if (numClusterPairsPerThread < 1) {
1088 "VerletClusterLists::fillClusterRanges(): numClusterPairsPerThread({}) is less than one, this is not "
1090 "and will lead to errors!",
1091 numClusterPairsPerThread);
1093 _clusterThreadPartition.resize(numThreads);
1095 size_t currentThread = 0;
1096 size_t currentNumClustersToAdd = 0;
1097 size_t numClusterPairsTotal = 0;
1098 bool threadIsInitialized =
false;
1100 for (
size_t currentTowerIndex = 0; currentTowerIndex < _towerBlock.size(); currentTowerIndex++) {
1101 auto ¤tTower = _towerBlock[currentTowerIndex];
1102 const auto firstOwnedClusterIndex =
1103 std::distance(currentTower.getClusters().begin(), currentTower.getFirstOwnedCluster());
1104 const auto firstTailHaloClusterIndex =
1105 std::distance(currentTower.getClusters().begin(), currentTower.getFirstTailHaloCluster());
1106 for (
size_t currentClusterInTower = firstOwnedClusterIndex; currentClusterInTower < firstTailHaloClusterIndex;
1107 ++currentClusterInTower) {
1108 auto ¤tCluster = currentTower.getCluster(currentClusterInTower);
1111 if (not threadIsInitialized) {
1112 _clusterThreadPartition[currentThread] = {currentTowerIndex, currentClusterInTower, 0};
1113 threadIsInitialized =
true;
1116 currentNumClustersToAdd++;
1117 numClusterPairsTotal += currentCluster.getNeighbors()->size();
1120 if (numClusterPairsTotal >= numClusterPairsPerThread * (currentThread + 1)) {
1122 _clusterThreadPartition[currentThread].numClusters += currentNumClustersToAdd;
1123 currentNumClustersToAdd = 0;
1128 if (currentThread >= numThreads) {
1130 threadIsInitialized =
true;
1132 threadIsInitialized =
false;
1137 if (not threadIsInitialized) {
1138 _clusterThreadPartition[currentThread] = {0, 0, 0};
1141 if (currentNumClustersToAdd != 0) {
1142 _clusterThreadPartition[currentThread].numClusters += currentNumClustersToAdd;
1145 while (++currentThread < numThreads) {
1146 _clusterThreadPartition[currentThread] = {0, 0, 0};
1157 _isValid.store(ValidityState::invalid, std::memory_order_relaxed);
1175 template <
bool regionIter>
1176 [[nodiscard]] std::tuple<size_t, size_t> advanceIteratorIndices(
1177 size_t cellIndex,
size_t particleIndex, IteratorBehavior iteratorBehavior,
const std::array<double, 3> &boxMin,
1178 const std::array<double, 3> &boxMax,
const std::array<double, 3> &boxMinWithSafetyMargin,
1179 const std::array<double, 3> &boxMaxWithSafetyMargin,
size_t endCellIndex)
const {
1184 auto towerIsRelevant = [&]() ->
bool {
1186 if (_towerBlock.size() == 1) {
1189 bool isRelevant =
true;
1190 if constexpr (regionIter) {
1192 const auto [towerLowCorner, towerHighCorner] = _towerBlock.getTowerBoundingBox(cellIndex);
1194 utils::boxesOverlap(towerLowCorner, towerHighCorner, boxMinWithSafetyMargin, boxMaxWithSafetyMargin);
1205 while (not towerIsRelevant() or particleIndex >= _towerBlock[cellIndex].getNumActualParticles()) {
1206 cellIndex += stride;
1211 if (cellIndex > endCellIndex) {
1212 return {std::numeric_limits<size_t>::max(), particleIndex};
1215 }
while (not containerIteratorUtils::particleFulfillsIteratorRequirements<regionIter>(
1216 _towerBlock[cellIndex][particleIndex], iteratorBehavior, boxMin, boxMax));
1219 return {cellIndex, particleIndex};
1232 size_t _clusterSize;
1237 size_t _numClusters{0};
1244 mutable std::vector<std::vector<Particle_T>> _particlesToAdd;
1251 [[nodiscard]]
bool particlesToAddEmpty(
int bufferID = -1)
const {
1252 if (bufferID == -1) {
1253 for (
auto &threadBuffer : _particlesToAdd) {
1254 if (not threadBuffer.empty()) {
1260 return _particlesToAdd[bufferID].empty();
1272 template <
class VecVec>
1273 void appendBuffersHelper(VecVec *additionalVectors, VecVec &outVec)
const {
1274 if (additionalVectors) {
1275 outVec.reserve(_particlesToAdd.size() + additionalVectors->size());
1276 outVec.insert(outVec.end(), additionalVectors->begin(), additionalVectors->end());
1278 outVec.reserve(_particlesToAdd.size());
1280 for (
auto &vec : _particlesToAdd) {
1281 outVec.push_back(&vec);
1288 std::vector<ClusterRange> _clusterThreadPartition;
1298 enum class ValidityState :
unsigned char {
1300 cellsValidListsInvalid = 1,
1301 cellsAndListsValid = 2
1307 std::atomic<ValidityState> _isValid{ValidityState::invalid};
1312 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
constexpr bool end() const
Dummy to make range-based for loops work.
Definition: ParticleContainerInterface.h:240
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:399
void reduce(Lambda reduceLambda, A &result, IteratorBehavior behavior=autopas::IteratorBehavior::ownedOrHalo)
Reduce properties of particles as defined by a lambda function.
Definition: VerletClusterLists.h:520
ContainerOption getContainerType() const override
Get the ContainerType.
Definition: VerletClusterLists.h:109
void traverseClusters(LoopBody &&loopBody)
Helper method to iterate over all clusters.
Definition: VerletClusterLists.h:807
void deleteHaloParticles() override
Deletes all halo particles.
Definition: VerletClusterLists.h:214
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:490
size_t size() const override
Get the number of all particles stored in this container (owned + halo + dummy).
Definition: VerletClusterLists.h:819
auto getClusterSize() const
Returns the number of particles in each cluster.
Definition: VerletClusterLists.h:877
void rebuildNeighborLists(TraversalInterface *traversal) override
Rebuilds the neighbor lists for the next traversals.
Definition: VerletClusterLists.h:777
BalancedTraversal::EstimatorFunction getLoadEstimatorFunction()
Generates the load estimation function depending on _loadEstimator.
Definition: VerletClusterLists.h:115
void setSkin(double skin)
Set the verlet skin length for the container.
Definition: VerletClusterLists.h:960
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:189
auto getTowersPerDimension() const
Returns the number of grids per dimension on the container.
Definition: VerletClusterLists.h:871
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:471
const std::array< double, 3 > & getHaloBoxMax() const
Get the upper corner of the halo box.
Definition: VerletClusterLists.h:940
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:286
void addParticleImpl(const Particle_T &p) override
Adds the given particle to the container.
Definition: VerletClusterLists.h:184
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:705
ContainerIterator< Particle_T, true, false > begin(IteratorBehavior behavior=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:414
void traverseClustersSequential(LoopBody &&loopBody)
Helper method to sequentially iterate over all owned clusters.
Definition: VerletClusterLists.h:1014
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:597
void computeInteractions(TraversalInterface *traversal) override
Iterates over all particle multiples (e.g.
Definition: VerletClusterLists.h:148
double getInteractionLength() const override
Return the interaction length (cutoff+skin) of the container.
Definition: VerletClusterLists.h:962
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:356
double getVerletSkin() const override
Return the verletSkin of the container verletSkin.
Definition: VerletClusterLists.h:954
void loadParticlesIntoSoAs(Functor *functor)
Loads all particles of the container in their correct SoA and generates the SoAViews for the clusters...
Definition: VerletClusterLists.h:891
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:257
Particle_T ParticleType
Type of the Particle.
Definition: VerletClusterLists.h:61
internal::ClusterTowerBlock2D< Particle_T > & getTowerBlock()
Getter for the cell block.
Definition: VerletClusterLists.h:932
auto getNumTowersPerInteractionLength() const
Returns the towers per interaction length.
Definition: VerletClusterLists.h:883
const std::array< double, 3 > & getBoxMin() const override
Get the lower corner of the container without halo.
Definition: VerletClusterLists.h:942
void deleteAllParticles() override
Deletes all particles.
Definition: VerletClusterLists.h:964
void fillClusterRanges(size_t numClusterPairsPerThread, int numThreads)
Fills in the cluster ranges of the cluster thread partition.
Definition: VerletClusterLists.h:1085
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:568
VerletClusterLists(const std::array< double, 3 > &boxMin, const std::array< double, 3 > &boxMax, double cutoff, double skin, size_t clusterSize, LoadEstimatorOption loadEstimator=LoadEstimatorOption::none)
Constructor of the VerletClusterLists class.
Definition: VerletClusterLists.h:97
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:539
size_t getNumberOfParticles(IteratorBehavior behavior) const override
Get the number of particles with respect to the specified IteratorBehavior.
Definition: VerletClusterLists.h:830
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:442
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:661
void traverseClustersParallel(LoopBody &&loopBody)
Helper method to iterate over all clusters in parallel.
Definition: VerletClusterLists.h:1036
const std::array< double, 3 > & getHaloBoxMin() const
Get the lower corner of the halo box.
Definition: VerletClusterLists.h:948
const internal::VerletClusterListsRebuilder< Particle_T >::NeighborListsBuffer_T & getNeighborLists() const
Get the neighbor lists buffer object.
Definition: VerletClusterLists.h:974
double getCutoff() const override
Return the cutoff of the container.
Definition: VerletClusterLists.h:950
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:921
auto getTowerSideLength() const
Returns the grid side length of the grids in the container.
Definition: VerletClusterLists.h:865
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:738
const std::array< double, 3 > & getBoxMax() const override
Get the upper corner of the container without halo.
Definition: VerletClusterLists.h:934
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:172
void setCutoff(double cutoff) override
Set the cutoff of the container.
Definition: VerletClusterLists.h:952
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:350
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:263
auto getNumClusters() const
Returns the number of clusters in this container.
Definition: VerletClusterLists.h:859
std::vector< Particle_T > updateContainer(bool keepNeighborListsValid) override
Updates the container.
Definition: VerletClusterLists.h:362
void rebuildTowersAndClusters(bool newton3)
Initializes a new VerletClusterListsRebuilder and uses it to rebuild the towers and the clusters.
Definition: VerletClusterLists.h:983
void calculateClusterThreadPartition()
Calculates a cluster thread partition that aims to give each thread about the same amount of cluster ...
Definition: VerletClusterLists.h:1058
void extractParticlesFromSoAs(Functor *functor)
Extracts all SoAs of the container into the particles.
Definition: VerletClusterLists.h:906
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:628
bool updateHaloParticle(const Particle_T &haloParticle) override
Update a halo particle of the container with the given haloParticle.
Definition: VerletClusterLists.h:194
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:1155
const auto & getClusterThreadPartition() const
Returns the cluster-thread-partition.
Definition: VerletClusterLists.h:853
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
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:70
size_t startIndexInTower
The index of the first cluster in its tower.
Definition: VerletClusterLists.h:78
size_t startTowerIndex
The index of the tower that contains the first cluster.
Definition: VerletClusterLists.h:74
size_t numClusters
The number of clusters in the range.
Definition: VerletClusterLists.h:82