80template <
class ParticleCell,
class Functor,
bool combineSoA = false>
96 explicit LCC01Traversal(
const std::array<unsigned long, 3> &dims,
Functor *functor,
const double interactionLength,
97 const std::array<double, 3> &cellLength, DataLayoutOption dataLayout,
bool useNewton3)
99 dataLayout, useNewton3),
100 _cellFunctor(functor, interactionLength ,
101 dataLayout, useNewton3),
131 return (combineSoA) ? TraversalOption::lc_c01_combined_SoA : TraversalOption::lc_c01;
137 void setSortingThreshold(
size_t sortingThreshold)
override { _cellFunctor.setSortingThreshold(sortingThreshold); }
141 using CellOffsetsType = std::conditional_t<decltype(utils::isPairwiseFunctor<Functor>())::value,
142 std::vector<std::vector<std::pair<
long, std::array<double, 3>>>>,
143 std::vector<std::tuple<
long,
long, std::array<double, 3>>>>;
146 using CellFunctorType = std::conditional_t<decltype(utils::isPairwiseFunctor<Functor>())::value,
158 inline void processBaseCell(std::vector<ParticleCell> &cells,
unsigned long x,
unsigned long y,
unsigned long z);
164 inline void processBaseCellPairwise(std::vector<ParticleCell> &cells,
unsigned long x,
unsigned long y,
171 inline void processBaseCellTriwise(std::vector<ParticleCell> &cells,
unsigned long x,
unsigned long y,
178 void computePairwiseOffsets();
184 void computeTriwiseOffsets();
192 template <std::size_t... I>
195 appendCell._particleSoABuffer);
202 void resizeBuffers();
208 CellOffsetsType _cellOffsets;
213 CellFunctorType _cellFunctor;
223 std::vector<std::vector<ParticleCell>> _combinationSlices;
228 std::vector<unsigned int> _currentSlices;
233 const unsigned int _cacheOffset;
236template <
class ParticleCell,
class Functor,
bool combineSoA>
239 computePairwiseOffsets();
241 computeTriwiseOffsets();
247template <
class ParticleCell,
class Functor,
bool combineSoA>
249 _cellOffsets.resize(2 * this->_overlap[0] + 1);
251 const auto interactionLengthSquare{this->_interactionLength * this->_interactionLength};
253 for (
long x = -this->_overlap[0]; x <= 0l; ++x) {
254 for (
long y = -this->_overlap[1]; y <= static_cast<long>(this->_overlap[1]); ++y) {
255 for (
long z = -this->_overlap[2]; z <= static_cast<long>(this->_overlap[2]); ++z) {
256 const std::array<double, 3> pos = {
257 std::max(0l, (std::abs(x) - 1l)) * this->_cellLength[0],
258 std::max(0l, (std::abs(y) - 1l)) * this->_cellLength[1],
259 std::max(0l, (std::abs(z) - 1l)) * this->_cellLength[2],
262 if (distSquare <= interactionLengthSquare) {
264 x, y, z, utils::ArrayUtils::static_cast_copy_array<long>(this->_cellsPerDimension));
265 const bool containCurrentOffset =
266 std::any_of(_cellOffsets[x + this->_overlap[0]].cbegin(), _cellOffsets[x + this->_overlap[0]].cend(),
267 [currentOffset](
const auto &e) {
return e.first == currentOffset; });
268 if (containCurrentOffset) {
271 for (
long ix = x; ix <= std::abs(x); ++ix) {
273 ix, y, z, utils::ArrayUtils::static_cast_copy_array<long>(this->_cellsPerDimension));
274 const size_t index = ix + this->_overlap[0];
278 std::array<double, 3> sortingDir = {
static_cast<double>(ix) * this->_cellLength[0],
279 static_cast<double>(y) * this->_cellLength[1],
280 static_cast<double>(z) * this->_cellLength[2]};
283 if (ix == 0 and y == 0 and z == 0) {
284 sortingDir = {1., 1., 1.};
288 if (y == 0l and z == 0l) {
290 _cellOffsets[index].insert(_cellOffsets[index].cbegin(), std::make_pair(offset, sortingDir));
292 _cellOffsets[index].emplace_back(offset, sortingDir);
301template <
class ParticleCell,
class Functor,
bool combineSoA>
302inline void LCC01Traversal<ParticleCell, Functor, combineSoA>::computeTriwiseOffsets() {
303 using namespace utils::ArrayMath::literals;
305 const int cubeSize = this->_overlap[0] * this->_overlap[1] * this->_overlap[2];
306 _cellOffsets.reserve(cubeSize * cubeSize / 4);
309 auto cellDistance = [&](
long x1,
long y1,
long z1,
long x2,
long y2,
long z2) {
310 return std::array<double, 3>{std::max(0l, (std::abs(x1 - x2) - 1l)) * this->_cellLength[0],
311 std::max(0l, (std::abs(y1 - y2) - 1l)) * this->_cellLength[1],
312 std::max(0l, (std::abs(z1 - z2) - 1l)) * this->_cellLength[2]};
315 const auto interactionLengthSquare{this->_interactionLength * this->_interactionLength};
316 _cellOffsets.emplace_back(0, 0, std::array<double, 3>{1., 1., 1.});
319 for (
long x1 = -this->_overlap[0]; x1 <= static_cast<long>(this->_overlap[0]); ++x1) {
320 for (
long y1 = -this->_overlap[1]; y1 <= static_cast<long>(this->_overlap[1]); ++y1) {
321 for (
long z1 = -this->_overlap[2]; z1 <= static_cast<long>(this->_overlap[2]); ++z1) {
323 const auto dist01 = cellDistance(0l, 0l, 0l, x1, y1, z1);
326 if (distSquare > interactionLengthSquare)
continue;
329 for (
long x2 = -this->_overlap[0]; x2 <= static_cast<long>(this->_overlap[0]); ++x2) {
330 for (
long y2 = -this->_overlap[1]; y2 <= static_cast<long>(this->_overlap[1]); ++y2) {
331 for (
long z2 = -this->_overlap[2]; z2 <= static_cast<long>(this->_overlap[2]); ++z2) {
333 const auto dist12 = cellDistance(x1, y1, z1, x2, y2, z2);
336 if (dist12Squared > interactionLengthSquare)
continue;
339 const auto dist02 = cellDistance(0l, 0l, 0l, x2, y2, z2);
342 if (dist02Squared > interactionLengthSquare)
continue;
345 x1, y1, z1, utils::ArrayUtils::static_cast_copy_array<long>(this->_cellsPerDimension));
348 x2, y2, z2, utils::ArrayUtils::static_cast_copy_array<long>(this->_cellsPerDimension));
351 if (offset2 <= offset1)
continue;
354 std::array<double, 3> sortDirection{};
356 sortDirection = {x2 * this->_cellLength[0], y2 * this->_cellLength[1], z2 * this->_cellLength[2]};
358 sortDirection = {x1 * this->_cellLength[0], y1 * this->_cellLength[1], z1 * this->_cellLength[2]};
369template <
class ParticleCell,
class Functor,
bool combineSoA>
370inline void LCC01Traversal<ParticleCell, Functor, combineSoA>::processBaseCell(std::vector<ParticleCell> &cells,
371 unsigned long x,
unsigned long y,
373 if constexpr (utils::isPairwiseFunctor<Functor>()) {
374 processBaseCellPairwise(cells, x, y, z);
375 }
else if constexpr (utils::isTriwiseFunctor<Functor>()) {
376 processBaseCellTriwise(cells, x, y, z);
379 "LCC01Traversal::processBaseCell(): Functor {} is not of type PairwiseFunctor or TriwiseFunctor.",
380 _functor->getName());
384template <
class ParticleCell,
class Functor,
bool combineSoA>
385inline void LCC01Traversal<ParticleCell, Functor, combineSoA>::processBaseCellPairwise(std::vector<ParticleCell> &cells,
386 unsigned long x,
unsigned long y,
389 ParticleCell &baseCell = cells[baseIndex];
390 const size_t cOffSize = _cellOffsets.size();
392 if constexpr (combineSoA) {
396 auto ¤tSlice = _currentSlices[threadID * _cacheOffset];
397 auto &combinationSlice = _combinationSlices[threadID];
400 if (x == this->_overlap[0]) {
402 for (
unsigned int offsetSlice = 0; offsetSlice < cOffSize; offsetSlice++) {
403 combinationSlice[offsetSlice]._particleSoABuffer.clear();
404 for (
const auto &offset : _cellOffsets[offsetSlice]) {
405 const unsigned long otherIndex = baseIndex + offset.first;
406 ParticleCell &otherCell = cells[otherIndex];
407 appendNeeded(combinationSlice[offsetSlice], otherCell,
414 const size_t midSlice = (currentSlice + this->_overlap[0] + 1) % cOffSize;
415 for (
size_t slice = (currentSlice + 1) % cOffSize; slice != midSlice; ++slice %= cOffSize, ++i) {
417 for (
const auto &offset : _cellOffsets[i]) {
418 const unsigned long otherIndex = baseIndex + offset.first;
419 ParticleCell &otherCell = cells[otherIndex];
420 newSize += otherCell.size();
422 combinationSlice[slice]._particleSoABuffer.resizeArrays(newSize);
425 for (
size_t slice = midSlice; slice != currentSlice; ++slice %= cOffSize, ++i) {
426 for (
auto offsetIndex = _cellOffsets[(i + 1) % cOffSize].size(); offsetIndex < _cellOffsets[i].size();
428 const unsigned long otherIndex = baseIndex + _cellOffsets[i][offsetIndex].first;
429 ParticleCell &otherCell = cells[otherIndex];
430 appendNeeded(combinationSlice[slice], otherCell,
435 combinationSlice[currentSlice]._particleSoABuffer.clear();
437 for (
const auto &offset : _cellOffsets.back()) {
438 const unsigned long otherIndex = baseIndex + offset.first;
439 ParticleCell &otherCell = cells[otherIndex];
440 appendNeeded(combinationSlice[currentSlice], otherCell,
444 ++currentSlice %= cOffSize;
448 for (
unsigned int slice = 0; slice < cOffSize; slice++) {
449 if (slice == (currentSlice + this->_overlap[0]) % cOffSize) {
452 auto startIndex = baseCell.size();
453 auto endIndex = combinationSlice[slice]._particleSoABuffer.size();
454 _functor->SoAFunctorPair(baseCell._particleSoABuffer,
455 {&(combinationSlice[slice]._particleSoABuffer), startIndex, endIndex},
false);
457 this->_cellFunctor.processCell(baseCell);
459 this->_cellFunctor.processCellPair(baseCell, combinationSlice[slice]);
463 for (
const auto &slice : _cellOffsets) {
464 for (
auto const &[offset, r] : slice) {
465 const unsigned long otherIndex = baseIndex + offset;
466 ParticleCell &otherCell = cells[otherIndex];
468 if (baseIndex == otherIndex) {
469 this->_cellFunctor.processCell(baseCell);
471 this->_cellFunctor.processCellPair(baseCell, otherCell, r);
478template <
class ParticleCell,
class Functor,
bool combineSoA>
479inline void LCC01Traversal<ParticleCell, Functor, combineSoA>::processBaseCellTriwise(std::vector<ParticleCell> &cells,
480 unsigned long x,
unsigned long y,
483 ParticleCell &baseCell = cells[baseIndex];
485 for (
auto const &[offset1, offset2, r] : _cellOffsets) {
486 const unsigned long otherIndex1 = baseIndex + offset1;
487 const unsigned long otherIndex2 = baseIndex + offset2;
488 ParticleCell &otherCell1 = cells[otherIndex1];
489 ParticleCell &otherCell2 = cells[otherIndex2];
491 if (baseIndex == otherIndex1 and baseIndex == otherIndex2) {
492 this->_cellFunctor.processCell(baseCell);
493 }
else if (baseIndex == otherIndex1 and baseIndex != otherIndex2) {
494 this->_cellFunctor.processCellPair(baseCell, otherCell2);
495 }
else if (baseIndex != otherIndex1 and baseIndex == otherIndex2) {
496 this->_cellFunctor.processCellPair(baseCell, otherCell1);
497 }
else if (baseIndex != otherIndex1 and otherIndex1 == otherIndex2) {
498 this->_cellFunctor.processCellPair(baseCell, otherCell1);
500 this->_cellFunctor.processCellTriple(baseCell, otherCell1, otherCell2, r);
505template <
class ParticleCell,
class PairwiseFunctor,
bool combineSoA>
506inline void LCC01Traversal<ParticleCell, PairwiseFunctor, combineSoA>::resizeBuffers() {
508 if (_combinationSlices.size() != numThreads) {
509 _combinationSlices.resize(numThreads);
510 const auto cellOffsetsSize = _cellOffsets.size();
511 std::for_each(_combinationSlices.begin(), _combinationSlices.end(),
512 [cellOffsetsSize](
auto &e) { e.resize(cellOffsetsSize); });
513 _currentSlices.resize(numThreads * _cacheOffset);
517template <
class ParticleCell,
class Functor,
bool combineSoA>
519 auto &cells = *(this->_cells);
520 if (not this->isApplicable()) {
521 if constexpr (combineSoA) {
523 "The C01 traversal with combined SoA buffers cannot work with data layout AoS and enabled newton3 (unless "
524 "only one thread is used)!");
527 "The C01 traversal cannot work with enabled newton3 (unless only one thread is used)!");
530 if constexpr (combineSoA) {
533 this->c01Traversal([&](
unsigned long x,
unsigned long y,
unsigned long z) { this->processBaseCell(cells, x, y, z); });
This class provides the base for traversals using the c01 base step.
Definition: C01BasedTraversal.h:25
Functor base class.
Definition: Functor.h:40
static constexpr std::array< typename Particle_T::AttributeNames, 0 > getNeededAttr()
Get attributes needed for computation.
Definition: Functor.h:77
This class provides the c01 traversal and the c01 traversal with combined SoA buffers.
Definition: LCC01Traversal.h:82
void setSortingThreshold(size_t sortingThreshold) override
Set the sorting-threshold for traversals that use the CellFunctor If the sum of the number of particl...
Definition: LCC01Traversal.h:137
void traverseParticles() override
Traverse the particles by pairs, triplets etc.
Definition: LCC01Traversal.h:518
LCC01Traversal(const std::array< unsigned long, 3 > &dims, Functor *functor, const double interactionLength, const std::array< double, 3 > &cellLength, DataLayoutOption dataLayout, bool useNewton3)
Constructor of the c01 traversal.
Definition: LCC01Traversal.h:96
TraversalOption getTraversalType() const override
Return a enum representing the name of the traversal class.
Definition: LCC01Traversal.h:130
void computeOffsets()
Computes all combinations of cells used in processBaseCell()
Definition: LCC01Traversal.h:237
bool isApplicable() const override
C01 traversals are only usable if useNewton3 is disabled and combined SoA buffers are only applicable...
Definition: LCC01Traversal.h:125
Interface for traversals used by the LinkedCell class.
Definition: LCTraversalInterface.h:18
Class for Cells of Particles.
Definition: ParticleCell.h:51
DataLayoutOption _dataLayout
The datalayout used by this traversal.
Definition: TraversalInterface.h:75
bool _useNewton3
If this traversal makes use of newton3.
Definition: TraversalInterface.h:80
A cell functor.
Definition: CellFunctor3B.h:24
A cell functor.
Definition: CellFunctor.h:25
static void exception(const Exception e)
Handle an exception derived by std::exception.
Definition: ExceptionHandler.h:63
constexpr T dot(const std::array< T, SIZE > &a, const std::array< T, SIZE > &b)
Generates the dot product of two arrays.
Definition: ArrayMath.h:233
constexpr std::array< T, SIZE > normalize(const std::array< T, SIZE > &a)
Generates a normalized array (|a| = 1).
Definition: ArrayMath.h:304
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
decltype(isTriwiseFunctorImpl(std::declval< FunctorT >())) isTriwiseFunctor
Check whether a Functor Type is inheriting from TriwiseFunctor.
Definition: checkFunctorType.h:56
decltype(isPairwiseFunctorImpl(std::declval< FunctorT >())) isPairwiseFunctor
Check whether a Functor Type is inheriting from PairwiseFunctor.
Definition: checkFunctorType.h:49
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
int autopas_get_thread_num()
Dummy for omp_set_lock() when no OpenMP is available.
Definition: WrapOpenMP.h:132
constexpr unsigned int DEFAULT_CACHE_LINE_SIZE
Default size for a cache line.
Definition: AlignedAllocator.h:21