AutoPas  3.0.0
Loading...
Searching...
No Matches
CellFunctor3B.h
Go to the documentation of this file.
1
7#pragma once
8
14namespace autopas::internal {
24template <class ParticleCell_T, class ParticleFunctor_T, bool bidirectional = true>
26 public:
36 explicit CellFunctor3B(ParticleFunctor_T &f, const double sortingCutoff, DataLayoutOption dataLayout, bool useNewton3)
37 : _functor(f), _sortingCutoff(sortingCutoff), _dataLayout(dataLayout), _useNewton3(useNewton3) {}
38
43 void processCell(ParticleCell_T &cell);
44
54 void processCellPair(ParticleCell_T &cell1, ParticleCell_T &cell2,
55 const std::array<double, 3> &sortingDirection = {0., 0., 0.});
56
65 void processCellTriple(ParticleCell_T &cell1, ParticleCell_T &cell2, ParticleCell_T &cell3,
66 const std::array<double, 3> &sortingDirection = {0., 0., 0.});
67
72 [[nodiscard]] DataLayoutOption::Value getDataLayout() const { return _dataLayout; }
73
78 [[nodiscard]] bool getNewton3() const { return _useNewton3; }
79
84 [[nodiscard]] bool getBidirectional() const { return bidirectional; }
85
93 void setAoSSortingThresholds(const SortingThresholdInfoInterface &aosSortingThreshold);
94
100 void setSoASortingThresholds(const SortingThresholdInfoInterface &soaSortingThreshold);
101
102 private:
109 [[nodiscard]] bool shouldUseSorting(size_t particleCount, const std::array<double, 3> &sortingDirection) const {
110 return particleCount >= _aosSortingThreshold and
111 (sortingDirection[0] != 0.0 or sortingDirection[1] != 0.0 or sortingDirection[2] != 0.0);
112 }
113
120 [[nodiscard]] static size_t resolveThreshold(const SortingThresholdInfoInterface &info) {
121 if (const auto *infoSingle = dynamic_cast<const SortingThresholdInfoSingle *>(&info)) {
122 return infoSingle->threshold;
123 }
124 throw utils::ExceptionHandler::AutoPasException(
125 "CellFunctor3b was called with wrong SortingThresholdInfo Type. (Supported is single)");
126 }
127
137 void processCellAoSImpl(ParticleCell_T &cell);
138
146 void processCellPairAoSImpl(ParticleCell_T &cell1, ParticleCell_T &cell2,
147 const std::array<double, 3> &sortingDirection);
148
159 void processCellTripleAoSImpl(ParticleCell_T &cell1, ParticleCell_T &cell2, ParticleCell_T &cell3,
160 const std::array<double, 3> &sortingDirection);
161
167 void processCellPairSoAImpl(ParticleCell_T &cell1, ParticleCell_T &cell2);
168
175 void processCellTripleSoAImpl(ParticleCell_T &cell1, ParticleCell_T &cell2, ParticleCell_T &cell3);
176
177 ParticleFunctor_T &_functor;
178
179 const double _sortingCutoff;
180
186 size_t _aosSortingThreshold{8};
187
193 size_t _soaSortingThreshold{100};
194
195 const DataLayoutOption::Value _dataLayout;
196
197 const bool _useNewton3;
198};
199
200template <class ParticleCell_T, class ParticleFunctor_T, bool bidirectional>
202 const SortingThresholdInfoInterface &aosSortingThreshold) {
203 _aosSortingThreshold = resolveThreshold(aosSortingThreshold);
204}
205
206template <class ParticleCell_T, class ParticleFunctor_T, bool bidirectional>
208 const SortingThresholdInfoInterface &soaSortingThreshold) {
209 _soaSortingThreshold = resolveThreshold(soaSortingThreshold);
210}
211
212template <class ParticleCell_T, class ParticleFunctor_T, bool bidirectional>
214 const bool isAoS = _dataLayout == DataLayoutOption::aos;
215 const bool isSoA = _dataLayout == DataLayoutOption::soa;
216
217 // Return early if the cell is empty.
218 if ((isSoA and cell._particleSoABuffer.size() == 0) or (isAoS and cell.isEmpty())) {
219 return;
220 }
221 // Avoid force calculations if the cell contains only halo particles or if the cell is empty (=dummy)
222 if (not cell.canHaveOwnedParticles()) {
223 return;
224 }
225
226 if (isAoS) {
227 processCellAoSImpl(cell);
228 } else if (isSoA) {
229 _functor.SoAFunctorSingle(cell._particleSoABuffer, _useNewton3);
230 }
231}
232
233template <class ParticleCell_T, class ParticleFunctor_T, bool bidirectional>
235 ParticleCell_T &cell1, ParticleCell_T &cell2, const std::array<double, 3> &sortingDirection) {
236 const bool isAoS = _dataLayout == DataLayoutOption::aos;
237 const bool isSoA = _dataLayout == DataLayoutOption::soa;
238
239 // Return early if a cell is empty.
240 if ((isSoA and (cell1._particleSoABuffer.size() == 0 or cell2._particleSoABuffer.size() == 0)) or
241 (isAoS and (cell1.isEmpty() or cell2.isEmpty()))) {
242 return;
243 }
244
245 if (not cell1.canHaveOwnedParticles()) {
246 // Nothing to do if cell1 has no owned particles and we don't write to cell2 particles.
247 if constexpr (not bidirectional) {
248 if (not _useNewton3) {
249 return;
250 }
251 }
252 // Nothing to do if both cells cannot have owned particles.
253 if (not cell2.canHaveOwnedParticles()) {
254 return;
255 }
256 }
257
258 if (isAoS) {
259 processCellPairAoSImpl(cell1, cell2, sortingDirection);
260 } else if (isSoA) {
261 processCellPairSoAImpl(cell1, cell2);
262 }
263}
264
265template <class ParticleCell_T, class ParticleFunctor_T, bool bidirectional>
267 ParticleCell_T &cell1, ParticleCell_T &cell2, ParticleCell_T &cell3,
268 const std::array<double, 3> &sortingDirection) {
269 const bool isAoS = _dataLayout == DataLayoutOption::aos;
270 const bool isSoA = _dataLayout == DataLayoutOption::soa;
271
272 // Return early if a cell is empty.
273 if ((isSoA and (cell1._particleSoABuffer.size() == 0 or cell2._particleSoABuffer.size() == 0 or
274 cell3._particleSoABuffer.size() == 0)) or
275 (isAoS and (cell1.isEmpty() or cell2.isEmpty() or cell3.isEmpty()))) {
276 return;
277 }
278
279 if (not cell1.canHaveOwnedParticles()) {
280 // Nothing to do if cell1 has no owned particles and we would only write to cell1 particles.
281 if constexpr (not bidirectional) {
282 if (not _useNewton3) {
283 return;
284 }
285 }
286 // Nothing to do if all three cells cannot have owned particles.
287 if (not cell2.canHaveOwnedParticles() and not cell3.canHaveOwnedParticles()) {
288 return;
289 }
290 }
291
292 if (isAoS) {
293 processCellTripleAoSImpl(cell1, cell2, cell3, sortingDirection);
294 } else if (isSoA) {
295 processCellTripleSoAImpl(cell1, cell2, cell3);
296 }
297}
298
299template <class ParticleCell_T, class ParticleFunctor_T, bool bidirectional>
301 // helper function
302 const auto interactParticles = [this](auto &p1, auto &p2, auto &p3) {
303 this->_functor.AoSFunctor(p1, p2, p3, this->_useNewton3);
304 if (not this->_useNewton3) {
305 this->_functor.AoSFunctor(p2, p1, p3, false);
306 this->_functor.AoSFunctor(p3, p1, p2, false);
307 }
308 };
309
310 if (cell.size() >= _aosSortingThreshold) {
311 SortedCellView<ParticleCell_T> cellSorted(cell, utils::ArrayMath::normalize(std::array<double, 3>{1.0, 1.0, 1.0}));
312
313 for (auto cellIter1 = cellSorted._particles.begin(); cellIter1 != cellSorted._particles.end(); ++cellIter1) {
314 auto &[p1Projection, p1Ptr] = *cellIter1;
315
316 for (auto cellIter2 = std::next(cellIter1); cellIter2 != cellSorted._particles.end(); ++cellIter2) {
317 auto &[p2Projection, p2Ptr] = *cellIter2;
318 if (std::abs(p2Projection - p1Projection) > _sortingCutoff) {
319 break;
320 }
321
322 for (auto cellIter3 = std::next(cellIter2); cellIter3 != cellSorted._particles.end(); ++cellIter3) {
323 auto &[p3Projection, p3Ptr] = *cellIter3;
324 if (std::abs(p3Projection - p1Projection) > _sortingCutoff or
325 std::abs(p3Projection - p2Projection) > _sortingCutoff) {
326 break;
327 }
328 interactParticles(*p1Ptr, *p2Ptr, *p3Ptr);
329 }
330 }
331 }
332 } else {
333 for (auto p1Ptr = cell.begin(); p1Ptr != cell.end(); ++p1Ptr) {
334 auto p2Ptr = p1Ptr;
335 ++p2Ptr;
336 for (; p2Ptr != cell.end(); ++p2Ptr) {
337 auto p3Ptr = p2Ptr;
338 ++p3Ptr;
339 for (; p3Ptr != cell.end(); ++p3Ptr) {
340 interactParticles(*p1Ptr, *p2Ptr, *p3Ptr);
341 }
342 }
343 }
344 }
345}
346
347template <class ParticleCell_T, class ParticleFunctor_T, bool bidirectional>
348void CellFunctor3B<ParticleCell_T, ParticleFunctor_T, bidirectional>::processCellPairAoSImpl(
349 ParticleCell_T &cell1, ParticleCell_T &cell2, const std::array<double, 3> &sortingDirection) {
350 const auto interactParticles = [this](auto &p1, auto &p2, auto &p3, const bool p2FromCell1) {
351 this->_functor.AoSFunctor(p1, p2, p3, this->_useNewton3);
352 if (not this->_useNewton3) {
353 if (p2FromCell1) {
354 this->_functor.AoSFunctor(p2, p1, p3, false); // because of no newton3 and p2 is still in cell1
355 } else {
356 if constexpr (bidirectional) {
357 this->_functor.AoSFunctor(p2, p1, p3, false);
358 }
359 }
360 if constexpr (bidirectional) {
361 this->_functor.AoSFunctor(p3, p1, p2, false);
362 }
363 }
364 };
365
366 if (shouldUseSorting(cell1.size() + cell2.size(), sortingDirection)) {
367 SortedCellView<ParticleCell_T> cell1Sorted(cell1, sortingDirection);
368 SortedCellView<ParticleCell_T> cell2Sorted(cell2, sortingDirection);
369
370 // Particle 1 from cell1
371 for (auto cellIter1 = cell1Sorted._particles.begin(); cellIter1 != cell1Sorted._particles.end(); ++cellIter1) {
372 auto &[p1Projection, p1Ptr] = *cellIter1;
373
374 // Particle 2 in cell1, particle 3 in cell2
375 for (auto cellIter2 = std::next(cellIter1); cellIter2 != cell1Sorted._particles.end(); ++cellIter2) {
376 auto &[p2Projection, p2Ptr] = *cellIter2;
377 if (std::abs(p2Projection - p1Projection) > _sortingCutoff) {
378 break;
379 }
380 for (auto &[p3Projection, p3Ptr] : cell2Sorted._particles) {
381 if (std::abs(p3Projection - p2Projection) > _sortingCutoff or
382 std::abs(p3Projection - p1Projection) > _sortingCutoff) {
383 break;
384 }
385 interactParticles(*p1Ptr, *p2Ptr, *p3Ptr, true);
386 }
387 }
388
389 // Particle 2 and 3 in cell 2
390 for (auto cellIter2 = cell2Sorted._particles.begin(); cellIter2 != cell2Sorted._particles.end(); ++cellIter2) {
391 auto &[p2Projection, p2Ptr] = *cellIter2;
392 if (std::abs(p2Projection - p1Projection) > _sortingCutoff) {
393 break;
394 }
395 for (auto cellIter3 = std::next(cellIter2); cellIter3 != cell2Sorted._particles.end(); ++cellIter3) {
396 auto &[p3Projection, p3Ptr] = *cellIter3;
397 if (std::abs(p3Projection - p2Projection) > _sortingCutoff or
398 std::abs(p3Projection - p1Projection) > _sortingCutoff) {
399 break;
400 }
401 interactParticles(*p1Ptr, *p2Ptr, *p3Ptr, false);
402 }
403 }
404 }
405 } else { // no sorting
406 // Particle 1 always from cell1
407 for (auto p1Ptr = cell1.begin(); p1Ptr != cell1.end(); ++p1Ptr) {
408 // Particle 2 still in cell1, particle 3 in cell2
409 auto p2Ptr = p1Ptr;
410 ++p2Ptr;
411 for (; p2Ptr != cell1.end(); ++p2Ptr) {
412 for (auto &p3 : cell2) {
413 interactParticles(*p1Ptr, *p2Ptr, p3, true);
414 }
415 }
416
417 // Particles 2 and 3 in cell2
418 for (auto p2Ptr = cell2.begin(); p2Ptr != cell2.end(); ++p2Ptr) {
419 auto p3Ptr = p2Ptr;
420 ++p3Ptr;
421 for (; p3Ptr != cell2.end(); ++p3Ptr) {
422 interactParticles(*p1Ptr, *p2Ptr, *p3Ptr, false);
423 }
424 }
425 }
426 }
427}
428
429template <class ParticleCell_T, class ParticleFunctor_T, bool bidirectional>
430void CellFunctor3B<ParticleCell_T, ParticleFunctor_T, bidirectional>::processCellTripleAoSImpl(
431 ParticleCell_T &cell1, ParticleCell_T &cell2, ParticleCell_T &cell3,
432 const std::array<double, 3> &sortingDirection) {
433 const auto interactParticles = [this](auto &p1, auto &p2, auto &p3) {
434 this->_functor.AoSFunctor(p1, p2, p3, this->_useNewton3);
435
436 if constexpr (bidirectional) {
437 if (not this->_useNewton3) {
438 this->_functor.AoSFunctor(p2, p1, p3, false);
439 this->_functor.AoSFunctor(p3, p1, p2, false);
440 }
441 }
442 };
443
444 if (shouldUseSorting(cell1.size() + cell2.size() + cell3.size(), sortingDirection)) {
445 SortedCellView<ParticleCell_T> cell1Sorted(cell1, sortingDirection);
446 SortedCellView<ParticleCell_T> cell2Sorted(cell2, sortingDirection);
447
448 for (auto &[p1Projection, p1Ptr] : cell1Sorted._particles) {
449 for (auto &[p2Projection, p2Ptr] : cell2Sorted._particles) {
450 if (std::abs(p2Projection - p1Projection) > _sortingCutoff) {
451 break;
452 }
453 for (auto &p3 : cell3) {
454 interactParticles(*p1Ptr, *p2Ptr, p3);
455 }
456 }
457 }
458 } else {
459 for (auto &p1 : cell1) {
460 for (auto &p2 : cell2) {
461 for (auto &p3 : cell3) {
462 interactParticles(p1, p2, p3);
463 }
464 }
465 }
466 }
467}
468
469template <class ParticleCell_T, class ParticleFunctor_T, bool bidirectional>
470void CellFunctor3B<ParticleCell_T, ParticleFunctor_T, bidirectional>::processCellPairSoAImpl(ParticleCell_T &cell1,
471 ParticleCell_T &cell2) {
472 _functor.SoAFunctorPair(cell1._particleSoABuffer, cell2._particleSoABuffer, _useNewton3);
473 if constexpr (bidirectional) {
474 if (not _useNewton3) {
475 _functor.SoAFunctorPair(cell2._particleSoABuffer, cell1._particleSoABuffer, false);
476 }
477 }
478}
479
480template <class ParticleCell_T, class ParticleFunctor_T, bool bidirectional>
481void CellFunctor3B<ParticleCell_T, ParticleFunctor_T, bidirectional>::processCellTripleSoAImpl(ParticleCell_T &cell1,
482 ParticleCell_T &cell2,
483 ParticleCell_T &cell3) {
484 _functor.SoAFunctorTriple(cell1._particleSoABuffer, cell2._particleSoABuffer, cell3._particleSoABuffer, _useNewton3);
485 if constexpr (bidirectional) {
486 if (not _useNewton3) {
487 _functor.SoAFunctorTriple(cell2._particleSoABuffer, cell1._particleSoABuffer, cell3._particleSoABuffer, false);
488 _functor.SoAFunctorTriple(cell3._particleSoABuffer, cell1._particleSoABuffer, cell2._particleSoABuffer, false);
489 }
490 }
491}
492} // namespace autopas::internal
A cell functor.
Definition: CellFunctor3B.h:25
DataLayoutOption::Value getDataLayout() const
Getter.
Definition: CellFunctor3B.h:72
void processCellTriple(ParticleCell_T &cell1, ParticleCell_T &cell2, ParticleCell_T &cell3, const std::array< double, 3 > &sortingDirection={0., 0., 0.})
Process the interactions between 3 particles, all located in a different cell.
Definition: CellFunctor3B.h:266
void processCell(ParticleCell_T &cell)
Process the interactions inside one cell.
Definition: CellFunctor3B.h:213
CellFunctor3B(ParticleFunctor_T &f, const double sortingCutoff, DataLayoutOption dataLayout, bool useNewton3)
The constructor of CellFunctor3B.
Definition: CellFunctor3B.h:36
bool getBidirectional() const
Getter.
Definition: CellFunctor3B.h:84
void processCellPair(ParticleCell_T &cell1, ParticleCell_T &cell2, const std::array< double, 3 > &sortingDirection={0., 0., 0.})
Process the interactions between the particles of cell1 with particles of cell2.
Definition: CellFunctor3B.h:234
bool getNewton3() const
Getter.
Definition: CellFunctor3B.h:78
void setSoASortingThresholds(const SortingThresholdInfoInterface &soaSortingThreshold)
Set the SoA sorting-threshold.
Definition: CellFunctor3B.h:207
void setAoSSortingThresholds(const SortingThresholdInfoInterface &aosSortingThreshold)
Set the aos-sorting-threshold for AoS traversals.
Definition: CellFunctor3B.h:201
This namespace is used for implementation specifics.
Definition: CellFunctor.h:21
constexpr std::array< T, SIZE > normalize(const std::array< T, SIZE > &a)
Generates a normalized array (|a| = 1).
Definition: ArrayMath.h:304
Polymorphic base for sorting-threshold storage.
Definition: SortingThresholdInfoInterface.h:18
Single threshold value struct.
Definition: SortingThresholdInfoSingle.h:18