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